1

ポッドキャストの MP3 ファイルを提供するために Amazon S3 を使用しています。Amazon はアクセス ログを提供しており、私はこれを取得して MySQL データベースに保存しています。データベースは次のようになります。

request_id  varchar(16)
time        int(10)     
file        varchar(255)        
sent        bigint(20)      
size        bigint(20)      
status      smallint(5)     
ip          varchar(39)         
referrer    varchar(255)        
user_agent  varchar(255)

これはポッドキャストであるため、膨大な数のヒットは (iTunes/iOS からの) 206 の範囲要求であり、各ファイルを小さなチャンクで要求します。

また、ファイルを複数回ダウンロードする人もいます。

だから私がやろうとしているのは、次のようなクエリを作成することです:

  • ファイルごと、IPごとに1つの結果のみを提供します(したがって、各IP /人は各ファイルに対して1つの「ヒット」としてのみカウントできます)。
  • ファイル/IP ごとに送信されたすべてのバイトの合計 (sent列) を合計するので、その特定のファイル/IP の組み合わせに対するすべての範囲要求の合計が何であるかがわかります。
  • ボーナス: ファイル/IP ごとの列の合計を比較し、sentバイトの合計がsize列の 75% 以上である場合にのみその結果を返します (現在、この比較は PHP でクエリ後に行っています)。

これは私が現在使用しているもので、機能していると信じていますが、完全な影響はGROUP BY私にとって謎です(たとえば、列の順序はGROUP BY重要ですか?):

SELECT FROM_UNIXTIME(time,'%M %D') as date, ip, file, SUM(sent) as sent, size
FROM stats
WHERE sent > 0 
AND size > 0
AND FROM_UNIXTIME(time, '%Y-%m-%d') >= '2012-09-01'
AND FROM_UNIXTIME(time, '%Y-%m-%d') <= '2012-09-30'
GROUP BY ip, file
ORDER BY time ASC, file ASC

ここで潜在的な落とし穴を見た人はいますか?

4

2 に答える 2

3

最初にあなたの質問に答えます:

"group by" の列の順序は、結果で返されるコンテンツに関しては重要ではありません。

常に同じグループ化と同じ集計値が得られます。ただし、列にインデックスがあり、group by の順序がインデックスの列の順序と一致しない場合、mysql のパフォーマンスに影響を与える可能性があります。パフォーマンスへの影響について論じた記事を見たことがあります。見つけたら、そのリンクを投稿します。

クエリに関しては、group by の一部ではないフィールドを選択していることに注意してください。これは SQL の標準ではありませんが、MySql では許可されています (MySql に禁止するように指示することは可能です)。知っておく必要があるのは、エンジンがグループを作成し、それらのフィールドに対して、グループ内で検出された最初の行から最初の値を選択するということです。クエリの方法によっては、正しい結果が保証されません。その理由は、結果が終了した後に order by が結果に適用されるためです。考えられる解決策はほとんどありませんが、サブクエリを使用し、グループ化が発生する前に最初の行が必要な行になるように内部に順序を設定することについて言及します。

SELECT in_tab.date, in_tab.ip, in_tab.file, SUM(in_tab.sent), in_tab.size
FROM (
  SELECT FROM_UNIXTIME(time,'%M %D') as date, ip, file, sent, size
  FROM stats
  WHERE sent > 0 
  AND size > 0
  AND FROM_UNIXTIME(time, '%Y-%m-%d') >= '2012-09-01'
  AND FROM_UNIXTIME(time, '%Y-%m-%d') <= '2012-09-30'
  ORDER BY time ASC
) in_tab
GROUP BY in_tab.ip, in_tab.file
ORDER BY in_tab.date ASC, in_tab.file ASC

ご覧のとおり、サブクエリの順序は、グループ化が開始される前に実行されます。そのため、外側のクエリによって作成された各グループでは、日付とサイズのフィールドが最初の行から取得されます。最も古い日付が必要な場合は、サブクエリで DESC に変更します)。外側の順序は最終結果をソートするために使用され、必要に応じて変更できます。

ボーナスとして、合計がサイズの 75% 以上の結果のみを取得するには、HAVING 句を使用できます。

SELECT in_tab.date, in_tab.ip, in_tab.file, SUM(in_tab.sent) as total_sent, in_tab.size
FROM (
  SELECT FROM_UNIXTIME(time,'%M %D') as date, ip, file, sent, size
  FROM stats
  WHERE sent > 0 
  AND size > 0
  AND FROM_UNIXTIME(time, '%Y-%m-%d') >= '2012-09-01'
  AND FROM_UNIXTIME(time, '%Y-%m-%d') <= '2012-09-30'
  ORDER BY time ASC
) in_tab
GROUP BY in_tab.ip, in_tab.file
HAVING total_sent > = 0.75 * in_tab.size
ORDER BY in_tab.date ASC, in_tab.file ASC

最善の解決策を検討することをお勧めします。標準SQLに切り替えることです。長期的にはより良く、より安全です。次に、必要なデータを 1 つのクエリでグループ化し、別のクエリで (または結合を使用して) 他の情報 (ファイル サイズや最小/最大日付など) を取得します。答えはすでに非常に長いので、それについて説明したり例を挙げたりするのをやめなければなりません。

于 2012-10-18T01:15:06.597 に答える
0

列の順序でグループ化することは重要です。最初の列でグループ化し、次に次の列でグループ化するため、A、B でグループ化すると、結果が A としてグループ化され、次に B でグループ化されます。これは、B が同様のデータである場合に重要です。

于 2012-10-18T00:03:08.817 に答える