1

したがって、SOが提供しなければならない最大のmySQLマインドのすべての力を利用する必要があります。各レコードのIPアドレスに基づいて詳細レコードを要約する必要があります。シナリオは次のとおりです。

つまり、「私のコンソーシアム内のどの学校がどの動画を何回視聴したか」を知りたいコンソーシアムがあります。SQL用語では、詳細レコードをカウントし、どのIP範囲に分類されるかでグループ化されます。

  1. 私たちはいくつかの大学コンソーシアムを持っています-それぞれがメンバーである少数の異なる学校を持っています。
  2. コンソーシアム内の各学校は、さまざまなIP範囲を使用して、これらの学校に提供するビデオにアクセスします。
  3. IP範囲はワイルドカードで指定されるため、各学校は「100.200.35.x、100.201.xx、100.202.39.50など」のように指定し、学校ごとの平均範囲数は10または15です。
  4. 要約する生のテキストログファイルはすでにデータベースにあり(ログエントリごとに1行)、ビデオファイルにアクセスした実際のIPアドレスが含まれています。
  5. 何億もの詳細レコードがあるので、これはかなりの期間実行される長く遅いプロセスであると私は完全に予想しています。
  6. ワイルドカードを表現される個々のIPに「分解」できるPHPスクリプトが存在しますが、これが最終的な答えになり、実行に数週間かかる可能性があると思います。

簡単にするために、アクセスされたビデオファイル名を参照し、そのログエントリをカウントするだけですが、実際には、開始/停止/期間などのすべての詳細があり、最終的には一部になりますこのソリューションの。)

コンソーシアムでは、次のようなレコードが記録されます:(ログの詳細を除くすべてのテーブルデザインが提案されます):

| id|consortium   |
| 10|Ivy League   |
| 20|California   |

そして、School/IPは次のよ​​うなものを記録します。

|  id|school     |consortium_id|
| 101|Harvard    |10           |
| 102|Yale       |10           |
| 103|UCLA       |20           |
| 104|Berkeley   |20           |

| id|school_id|ip_range         |
|  1| 101     |100.200.x.x      |
|  2| 101     |100.201.65.x     |
|  3| 101     |100.202.39.50    |
|  4| 101     |100.202.39.51    |
|  5| 101     |100.200.x.x      |
|  6| 101     |100.201.65.x     |
|  7| 101     |100.202.39.50    |

そして、詳細は次のようなものを記録します。

|session     |ip_address     |filename          |
|560554790925|100.202.390.500|history101.mp4    |
|406417611526|43.22.90.5     |newsreel.mp4      |
|650423700223|100.202.39.50  |history101.mp4    |
|650423700223|100.202.50.12  |science101.mp4    |
|513057324209|100.202.39.56  |history101.mp4    |

私はmySQLをかなり便利だと思うのが好きですが、これはmySQLを拡張しており、誰かが提供する可能性のある素晴らしい関数または一連のステップがあることを望んでいます。

4

2 に答える 2

2

既存のデータ構造を使用して、次のように文字列照合を行うことができます(ただし、あまり効率的ではありません)。

SELECT   schools.school, detail.filename, COUNT(*)
FROM     schools
    JOIN ipranges ON schools.id = ipranges.school_id
    JOIN detail   ON detail.ip_address LIKE REPLACE(ipranges.ip_range, 'x', '%')
WHERE    schools.consortium_id = ?
GROUP BY schools.school, detail.filename

より良い方法は、IP範囲をネットワークアドレスとプレフィックス長として保存することです。

ALTER TABLE ipranges
  ADD COLUMN network INT UNSIGNED,
  ADD COLUMN prefix  TINYINT;
UPDATE ipranges SET
  network = INET_ATON(REPLACE(ip_range, 'x', 0)),
  prefix  = 32 - 8*(CHAR_LENGTH(ip_range) - CHAR_LENGTH(REPLACE(ip_range,'x',''));
ALTER TABLE ipranges
  DROP COLUMN ip_range;

ALTER TABLE detail
  ADD COLUMN ip_address_new INT UNSIGNED;
UPDATE detail SET
  ip_address_new = INET_ATON(ip_address);
ALTER TABLE detail
  DROP COLUMN ip_address,
  CHANGE ip_address_new ip_address INT UNSIGNED;

次に、それは単にいくつかのビット比較を実行する場合です:

SELECT   schools.school, detail.filename, COUNT(*)
FROM     schools
    JOIN ipranges ON schools.id = ipranges.school_id
    JOIN detail   ON detail.ip_address & ~((1 << 32 - ipranges.prefix) - 1)
                   = ipranges.network
WHERE    schools.consortium_id = ?
GROUP BY schools.school, detail.filename
于 2012-05-31T16:34:18.510 に答える
0
SELECT D.filename, S.school, COUNT(D.*)
FROM detail_records AS D
     INNER JOIN ip_map AS I ON D.ip_address LIKE CONCAT(SUBSTRING(I.ip_range, 1, LOCATE('x', I.ip_range)-1), '%')
     INNER JOIN school AS S ON S.id = I.school_id
     INNER JOIN consortium AS C ON C.id = S.consortium_id
WHERE S.consortium_id = <consortium identifier>
GROUP BY D.filename, S.school
于 2012-05-31T16:51:35.560 に答える