2009-07-17 13 views
7

3つのカラムに基づいた複合インデックスがあり、そのうちの2つはクエリで制約され、3つ目はorder by節であり、mysqlはインデックスをソートに使用しません。インデックスをソート用に最適化するためにmysqlクエリを最適化する

 
explain select * from videos where public_private='public' and approved='yes' order by number_of_views desc; 

+----+-------------+--------+------+--------------------------------+------+---------+------+---------+-----------------------------+ 
| id | select_type | table | type | possible_keys     | key | key_len | ref | rows | Extra  | 
+----+-------------+--------+------+--------------------------------+------+---------+------+---------+-----------------------------+ 
| 1 | SIMPLE  | videos | ALL | approved,approved_3,approved_2 | NULL | NULL | NULL | 1476818 | Using where; Using filesort | 
+----+-------------+--------+------+--------------------------------+------+---------+------+---------+-----------------------------+ 

テーブル構造は次のとおりです。

CREATE TABLE `videos` (
    `indexer` int(9) NOT NULL auto_increment, 
    `user_id` int(9) default NULL, 
    `public_private` varchar(24) default NULL, 
    `approved` varchar(24) default NULL, 
    `number_of_views` int(9) default NULL, 
    PRIMARY KEY (`indexer`), 
    KEY `approved` (`approved`,`user_id`), 
    KEY `approved_3` (`approved`,`public_private`,`indexer`), 
    KEY `approved_2` (`approved`,`public_private`,`number_of_views`), 
) ENGINE=MyISAM AUTO_INCREMENT=1969091 DEFAULT CHARSET=utf8 | 

私は結果をソートするためにインデックスを使用してMySQLを強制的に行う必要がありますか?

答えて

13

を実行するために、すべての3を使用している場合にのみ、その特定のキーを使用しますテーブル内のデータ。このような状況では、MySQLオプティマイザは多くの場合、インデックス全体の追加読み込みの問題を克服してデータを選択するよりも実際に速いので、テーブルスキャンを実行してインデックスを完全に無視することを選択します。この場合、public_private='yes' and approved='yes'がテーブルの良い部分と一致していると推測しています。したがって、このためインデックスを使用してMySQLをスキップすると、ソートに使用できません。

あなたは本当にそれがインデックスを使用したい場合は、解決策はFORCE INDEXを使用することです:

select * from videos FORCE INDEX (approved_2) where public_private='public' and approved='yes' order by number_of_views desc; 

しかし、私は確かに何を取得していることよりも、実際に高速であることを確認するためにいくつかのテストを実行しますMySQLオプティマイザが選択したもの明らかにオプティマイザdoes have some issuesは注文のための選択をしているので、あなたは間違いなくこのショットを与え、あなたが改善されたパフォーマンスを得るかどうかを見ることができます。

+0

FORCE INDEXが問題を解決しました。クエリは今よりはるかに高速に実行され、データベースの大部分に一致するクエリについては正しいです。 –

+0

良いこと、うまくいきました。 – zombat

-2

複合キーの順序が重要です。私はルールを忘れるが、違う順序で試してみる。

-2

number_of_views列に別のインデックスを追加し、それが動作するかどうかを確認してください。

キーは3列の組み合わせであれば、私はあなたが持っているクエリは、おそらくかなりの割合を一致していることを信じて操作

+0

いいえ:キーが3つの列の組み合わせである場合、最初の列または最初の2つの列または3つの列の組み合わせを使用しているときにその特定のキーを使用します。 –

1

複合キーでの順序は重要です。

KEY `approved_2` (`approved`,`public_private`,`number_of_views`) 

へ:左から右へのMySQLの仕事で

KEY `approved_2` (`number_of_views`,`approved`,`public_private`) 

コンポジットキー、あなただけのnumber_of_viewsapproved_2キー、変更を使用してソートしたい場合。上記の例では、キーはnumber_of_viewsapprovedを使用して宣言し、public_private暗黙的には上のインデックスを作成します:これは動作するはず

  • number_of_views
  • number_of_viewsapproved
  • number_of_viewsapprovedpublic_private
+0

この解決策は、最初の2つのフィールドをフィルタリングし、3つ目のフィールドを並べ替えることの可能性を「MySQL」から奪います。 – Quassnoi

+0

彼はなぜ索引がソートに使われなかったのか尋ねました。 –

+1

あなたが提案しているインデックスはソートにのみ使用できます。 '@ op 'によって提案されたインデックスは、ソートのために*と*をフィルタリングするために使用できます。インデックスはフィルタリングに使用することはできませんが、ソートに使用する(または使用しない)こともできます。 – Quassnoi

0

`select * from videos where approved='yes' and public_private='public' order by number_of_views desc;` 

number_of_viewsに別のインデックスを作成するだけです。

これは機能する必要があります。

(mysqlのは、つまり、あなたは左から3つすべてを使用することができます。このシーケンスで使用されていないのであればapprovedであなたのインデックス、public_privateは、number_of_viewsは動作しません。基本的には左右のシーケンスを次の2左からか、ほとんど1左左端の数字を使用しないと機能しません)。

別のインデックスを使用すると、number_of_viewsが自動的にソートされますが、これはorder byに役立ちます。これは確かです。

+0

索引 'number_of_views'を追加するだけでは、' where'条件を満たす索引が考慮されるため、問題を解決できません。 OPの答えでは、 'approved_2'インデックスが使われ、' approved、public_private'と 'number_of_views'のインデックスは別々に使われるべきです。 –