2

item_tag_map2つの列がitem_idありtag_id、両方にインデックスがあります。

データサンプルは次のとおりです。

item_id     tag_id
1           1
1           3
4           7
1           5
3           1
3           8
6           8
10          4

次に、タグ1、2、3、5を持つアイテムIDを取得し、すべてのタグの総数で結果を並べ替えます。

結果のサンプルは次のとおりです。

item_id     count(m.tag_id)
1           3
3           1

私が試したSQLは次のとおりです。

SELECT m.item_id,count(m.tag_id) from item_tag_map AS m
WHERE tag_id in(1,2,3,5)
GROUP BY m.item_id
ORDER BY count(m.tag_id)
LIMIT 10

このテーブルには約1万行あり、クエリは非常に低速でした。すべてのステートメントを削除しようとしましたcountが、以前よりも非常に速くなりました。

なぜcountこのクエリの速度が低下するのでしょうか。このクエリを最適化して高速化するにはどうすればよいですか?

4

1 に答える 1

4

これは のためですORDER BY COUNT(m.tag_id)
MySQL は、 の各値のカウントを計算するために、すべての行を取得する (つまり、完全なテーブル スキャンを実行する) 必要がありますitem_id

この場合、MySQL はインデックスを使用できません。(見ればわかるかもしれませんがEXPLAIN SELECT ..)

COUNT()からを削除すると、MySQL はソートにインデックスを使用できます。ORDER BY


これに対する考えられる解決策の 1 つは、マテリアライズド ビューを作成することです。このビューでは、DBMS がtag_id値のカウントを別のitem_idテーブルにキャッシュします。

MySQL はマテリアライズド ビューをネイティブにサポートしていませんが、それらをシミュレートできます。
最初に問題のクエリ ( ) を使用して一度テーブルを作成し、その後、トリガーINSERT INTO tag_counts SELECT ...を使用して更新し続けることができます。または、このプロセスを自動化するFlexViews という名前のサードパーティ ソフトウェアがあります。ON [INSERT | DELETE]

それが、週に数百万行の統計データベースを反応的に保つ方法です。

于 2012-10-29T09:09:24.167 に答える