2

3つの大きなテーブル(10k、10k、および100M行)があり、それらの結合を単純にカウントしようとしています。ここでは、結合されたすべての列にインデックスが付けられます。COUNT(*)に時間がかかるのはなぜですか?また、どうすれば(トリガーと実行中の要約なしで)それを高速化できますか?

mysql> describe SELECT COUNT(*) FROM `metaward_alias` INNER JOIN `metaward_achiever` ON (`metaward_alias`.`id` = `metaward_achiever`.`alias_id`) INNER JOIN `metaward_award` ON (`metaward_achiever`.`award_id` = `metaward_award`.`id`) WHERE `metaward_award`.`owner_id` = 8;
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
| id | select_type | table             | type   | possible_keys                                         | key                        | key_len | ref                             | rows | Extra       |
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
|  1 | SIMPLE      | metaward_award    | ref    | PRIMARY,metaward_award_owner_id                       | metaward_award_owner_id    | 4       | const                           | 1552 |             | 
|  1 | SIMPLE      | metaward_achiever | ref    | metaward_achiever_award_id,metaward_achiever_alias_id | metaward_achiever_award_id | 4       | paul.metaward_award.id          | 2498 |             | 
|  1 | SIMPLE      | metaward_alias    | eq_ref | PRIMARY                                               | PRIMARY                    | 4       | paul.metaward_achiever.alias_id |    1 | Using index | 
+----+-------------+-------------------+--------+-------------------------------------------------------+----------------------------+---------+---------------------------------+------+-------------+
3 rows in set (0.00 sec)

しかし、実際にクエリを実行するには約10分かかります。私は、MyISAMを使用しているため、その間、テーブルは完全にロックダウンされます。

4

3 に答える 3

3

その理由は、3つのテーブルに対して大規模な結合を行うためだと思います(最初にwhere句を適用しないと、結果は10k * 10k * 100M = 10 16行になります)。結合の順序を変更してみてください(たとえば、から始めて、結合にかかる時間metaward_awardだけを確認してから、プラグインしてみてください。サブクエリを使用して、優先する評価順序を強制することもできます)。metaward_achievermetaward_alias

それでも問題が解決しない場合は、たとえば特定ののエイリアスの数を保存するなどして、データを非正規化する必要がありますmetaward_achiever。次に、1つの結合を完全に削除します。metaward_awardデータが更新される方法と頻度に応じて、の合計をキャッシュすることもできます。

他に役立つかもしれないことは、すべてのデータベースコンテンツをRAMに取り込むことです:-)

于 2009-09-17T07:01:36.767 に答える
1

次のインデックスがあることを確認してください。

metaward_alias      id
metaward_achiever   alias_id
metaward_achiever   award_id
metaward_award      id
metaward_award      owner_id

多くの人が特定の列を頼りにすることを提案することもあると思いますが、MySqlではこれはクエリに何の違いもありません。

更新

結合されたテーブルの1つではなく、メインテーブルに条件を設定することもできます。それはあなたに同じ結果を与えるでしょう、しかしそれはより速いかもしれません(私はMySqlがどれほど賢いかわかりません):

SELECT COUNT(*) FROM `metaward_award` 
   INNER JOIN `metaward_achiever` 
      ON (`metaward_achiever`.`award_id` = `metaward_award`.`id`) 
   INNER JOIN `metaward_alias` 
      ON (`metaward_alias`.`id` = `metaward_achiever`.`alias_id`) 
WHERE `metaward_award`.`owner_id` = 8
于 2009-09-17T06:50:48.730 に答える
1

そのクエリには10分は長すぎます。本当に小さなキーキャッシュが必要だと思います。次のコマンドでサイズをバイト単位で取得できます。

SELECT @@key_buffer_size

まず、 ANALYZETABLEまたはOPTIMIZETABLEを実行する必要があります。インデックスを並べ替えて、パフォーマンスをわずかに向上させることができます。

また、列にもっとコンパクトなタイプを使用できるかどうかも確認する必要があります。たとえば、1600万を超える所有者、賞、またはエイリアスを持たない場合は、INT列をMEDIUMINT(もちろんUNSIGNED)に変更できます。場合によってはSMALLINTでさえありますか?これにより、インデックスのフットプリントが削減され、より多くのインデックスがキャッシュに収まります。

于 2009-09-17T13:11:34.403 に答える