2つのテーブルがあります。1つにはダウンロードしたURLの履歴が含まれ、もう1つのテーブルには各URLの詳細が含まれています。
次のクエリは、過去1時間の繰り返し回数でURLをグループ化します。
SELECT COUNT(history.url) as total, history.url
FROM history
WHERE history.time > UNIX_TIMESTAMP()-3600
GROUP BY history.url
ORDER BY COUNT(history.url) DESC
LIMIT 30
上記のクエリの実行には約800msかかりますが、十分な速度ではありませんが、許容範囲ですが、
ただし、キャッシュテーブルと結合すると、新しいクエリの実行に約25秒かかり、非常に遅くなります。
SELECT th.total, th.url, tc.url, tc.json
FROM (SELECT COUNT(history.url) as total, history.url
FROM history
WHERE history.time > UNIX_TIMESTAMP()-3600
GROUP BY history.url
ORDER BY COUNT(history.url) DESC
LIMIT 30
) th
INNER JOIN (SELECT cache.url, cache.json FROM cache) tc
ON th.url = tc.url
GROUP BY th.url
ORDER BY th.total DESC
LIMIT 30
「tc」では、キャッシュテーブル全体がロードされており、100万以上のエントリが含まれているため、これが発生している可能性があると思います。
最初のクエリを使用し、プログラムで結果を反復処理してから、結果ごとにキャッシュからSELECTクエリを実行すると、はるかに高速になります。とにかく2番目のクエリを高速化する方法はありますか?
追伸InnoDBを使用しています
一般に、JOIN述語またはWHERE句に参加する列にインデックスを付けることをお勧めします。よくある間違いは、複数列のインデックスを減らすのではなく、1列のインデックスをいくつか作成することです。ここでは、URLと履歴の時間の両方からメリットを得ることができます(これらのテーブルに対するすべてのクエリを確認すると、これらのインデックスに列を追加できることがわかります)。
CREATE INDEX x01_history_url ON HISTORY (URL, TIME);
CREATE INDEX x01_cache_url ON CACHE (URL);
次に、クエリのネストを解除してみます。 MySQLは、実行できるクエリ書き換えの種類に制限があるため、ネストにより不要なオーバーヘッドが発生する可能性があります。
SELECT COUNT(th.url) as total, tc.url, tc.json
FROM history th
JOIN cache tc
ON th.url = tc.url
WHERE th.time > UNIX_TIMESTAMP()-3600
GROUP BY tc.url, tc.json
ORDER BY COUNT(th.url) DESC
LIMIT 30
このクエリは意味的にクエリとは異なるため、異なる結果が得られる可能性があります。これが問題である場合は、以前と同じようにサブクエリでLIMIT 30構成を維持することをお勧めします。同様の制限をCACHEに追加できるかどうかを検討することもできます。合計30行を取得するために調査する必要があるCACHE行の数に上限はありますか?
INNER JOIN (SELECT cache.url, cache.json
FROM cache
ORDER BY ? LIMIT ?) tc
最初のクエリの場合:
_SELECT COUNT(*) as total, -- * is the common pattern
url
FROM history
WHERE time > NOW() - INTERVAL 1 HOUR
GROUP BY url
ORDER BY COUNT(*) DESC
LIMIT 30
INDEX(time, url) -- in this order
INDEX(url, time) -- maybe this order
_
両方のインデックスを使用します。 MySQLのバージョンや時間範囲が異なれば、一方のインデックスともう一方のインデックスを使用する場合があります。
2番目のクエリでは、派生テーブルを不必要に使用しないでください。
_INNER JOIN (SELECT cache.url, cache.json FROM cache) tc
ON th.url = tc.url
_
->
_INNER JOIN cache tc
ON th.url = tc.url
_
そしてcache
にはINDEX(url)
が必要です。
2つのテーブルは1:1または1:多数または多数:1または多数:多数ですか?外側の_GROUP/ORDER/LIMIT
_に違いが生じる場合があります。
その間、テーブルに_SHOW CREATE TABLE
_を指定してください。