2016-11-30 16 views
1

私は、完了までに約14秒かかっているかなり単純なクエリを持っています。ここではここクエリmySQLの特定のクエリのインデックスを最適化する

SELECT * 
FROM opportunities 
WHERE cid = 7785 
    AND STATUS != 4 
    AND otype != 200 
    AND links > 0 
    AND ontopic != 'F' 
ORDER BY links DESC 
LIMIT 0, 100; 

は、テーブルスキーマが

CREATE TABLE `opportunities` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `cid` int(11) NOT NULL, 
    `url` varchar(900) CHARACTER SET utf8 NOT NULL, 
    `status` tinyint(4) NOT NULL, 
    `links` int(11) NOT NULL, 
    `otype` int(11) NOT NULL, 
    `reserved` tinyint(4) NOT NULL, 
    `ontopic` varchar(3) CHARACTER SET utf8 NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `cid` (`cid`,`url`), 
    KEY `cid1` (`cid`), 
    KEY `url` (`url`), 
    KEY `otype` (`otype`), 
    KEY `reserved` (`reserved`), 
    KEY `ontopic` (`ontopic`), 
    KEY `status` (`status`), 
    KEY `links` (`links`), 
    KEY `ontopic_links` (`ontopic`,`links`), 
    KEY `cid_status_otype_links_ontopic` (`cid`,`status`,`otype`,`links`,`ontopic`) 
) ENGINE=InnoDB AUTO_INCREMENT=13022832 DEFAULT CHARSET=latin1 

です

...私は場所に正しいインデックスを持っていると思うが、私はわかりませんEXPLAINコマンドの結果は次のとおりです

id: 1 
select_type: Simple 
table: opportunities 
partitions: null 
type: range 
possible_keys: cid,cid1,otype,ontopic,status,links,ontopic_links,cid_status_otype_links_ontopic 
key: links 
keylen: 4 
ref: null 
rows: 1531552 
filtered: 0.33 
Extra: Using index condition; Using where 

思考/質問

私はクエリを実行するために、「リンク」キーを使用していることがそれを正しく読んでいますか?なぜ私のクエリのすべての条件をカバーするcid_status_otype_links_ontopicのようなより完全なインデックスを使用しないのですか?

ありがとうございます!

としては、あなたがLIMIT 0100を削除するクエリに一致30961件の結果があります

を要求しました。興味深いことに、 "count()"コマンドはほぼ即座に戻ります。

+0

このクエリから返されるレコード数はいくつですか? 'LIMIT'節を削除し、' COUNT(*) 'を実行して、戻ったレコード数を報告してください。 –

+0

応答ありがとう!私は30,961結果を返します。 – user2648990

答えて

2

不等式の比較の使用については、の範囲という条件でカウントされるのは面白いことです。ある

、平等は一つの値と一致したが、平等以外(!=><INBETWEEN)。

複数の値を一致させると、範囲条件で使用されるインデックスの最初の列のみが最適化されることを意味します。インデックスcid_status_otype_links_ontopicには、クエリの条件に記載されているすべての列があると思われますが、最初の2つだけが使用されます。 cidの同等性の比較があるため、最初です。 2番目の列は、次の列が不等式比較で使用されるため、インデックスの列を使用して停止する部分です。*

エビデンス:そのインデックスを強制的に使用できる場合は、keylenのフィールドが表示されます。 EXPLAIN結果は、cid(4バイト)+ status(1バイト)のサイズである5だけを示します。

インデックスを使用すると、インデックス番号のインデックスを使用するほうが、インデックス順にアクセスできるようになるため、MySQLオプティマイザが明らかに予測しています。ORDER BYでの並べ替え順序と同じです。

エビデンス: EXPLAINメモの「Using Filesort」を参照してください。

これは他のインデックスの1つを使用するよりも本当に優れていますか?多分そうでないかもしれません。オプティマイザの予測は必ずしも完全ではありません。

あなたは、オプティマイザの選択を上書きするindex hintを使用することができます。

SELECT * FROM opportunities USE INDEX (cid_status_otype_links_ontopic) WHERE ... 

は、そのクエリのEXPLAINやEXPLAINあなたの他と比較しない、それを試してみてください。次に、両方のクエリを実行し、どちらが確実に高速であるかを確認します。

(*実際には、インデックスカラムの使い方について脚注を追加する必要があります。MySQL 5.6以降では、EXPLAINの「Using Index Condition」という注釈が表示されたときに、しかしそれは全く同じではありません。詳細はこちらをご覧ください:https://dev.mysql.com/doc/refman/5.6/en/index-condition-pushdown-optimization.html

2
  • 5列のインデックスを使用してすべての行を移動し、結果を並べ替えて100行を配信する必要があります。

  • 有用性が高いと思われる唯一のインデックスはINDEX(cid, links)です。これはcid=でテストされている唯一のカラムであるため、linksORDER BYおよびLIMITに役立つためです。 !=テストでは多くの行をフィルタリングする必要があります。

  • statusotypeは多値ですか?いずれかの値が2つしかない場合は、!==に変更してインデックスに追加すると効果的です。

  • 実際にすべての列(SELECT *)が必要ですか?そうでない場合はの場合は大きい欄(url)は必要ありません。

More on writing indexes