2012-11-26 10 views
5

私は、次の2つなインデックスインデックスが作成される順序は、クエリオプティマイザが選択するインデックスに影響しますか?

ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address); 
ALTER TABLE requests ADD INDEX is_cached(exec_date, cached); 

を作成する場合show index from requestsの出力は、私は、クエリを強制したいと思いますしかし、私は次のクエリ

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes 
FROM requests 
GROUP BY exec_date; 

id select_type table type possible_keys key   key_len ref rows Extra 
1 SIMPLE requests index NULL   daily_ips 263 NULL 436695 

を持って、次の

Table  Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment 
requests 1   daily_ips 1    exec_date A   413   NULL NULL YES BTREE  
requests 1   daily_ips 2    ip_address A   218334  NULL NULL YES BTREE  
requests 1   is_cached 1    exec_date A   165   NULL NULL YES BTREE  
requests 1   is_cached 2    cached  A   165   NULL NULL YES BTREE  

ですオプティマイザはdaily_ipsインデックスの代わりにis_cachedインデックスを使用します。

私はdaily_ipsインデックスを削除し、同じEXPLAINステートメントを実行後、再び

ALTER TABLE requests DROP INDEX daily_ips; 
ALTER TABLE requests ADD INDEX daily_ips(exec_date, ip_address); 

それを追加した場合、クエリオプティマイザはis_cachedインデックスを選択します。

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE requests index NULL is_cached 6 NULL 440493 Using index 

クエリオプティマイザは、追加された順序に基づいてインデックスを選択することが予想されますか?

クエリオプティマイザにどのインデックスを使用するかを教えてください。

+0

私は、インデックスがテーブルスキャンを行うためにのみ使用されていると信じています。実際にインデックスを使用する場合は、キャッシュ上のwhere条件でカウントする2つのクエリにクエリを再構成する必要があります。 (ただし、キャッシュはインデックスの最初のキーでなければなりません)。基本的に、CASEによってテーブルスキャンが実行されています。 – Corbin

+1

私は自分の答えを更新しました –

+0

@Corbinあなたが推薦するクエリをどうやって作成するのか分かりません。どのようにして正確に2つのクエリにクエリを再構成できますか(サンプルコードはどれくらい高く評価されますか) – user784637

答えて

2

クエリの実行に使用するインデックスsholudを指定できます。

これを試してみてください:

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes 
FROM requests USE INDEX(is_cached) 
GROUP BY exec_date; 

Differnce USE INDEX間とFORCE INDEX

を使用するINDEX(index_list)を指定することで、テーブル内の行を見つけるために、名前のインデックスの一つだけを使用するようにMySQLを伝えることができます。代替構文IGNORE INDEX(index_list)は、特定のインデックスまたはインデックスを使用しないようにMySQLに指示するために使用できます。これらのヒントは、MySQLが可能なインデックスのリストから間違ったインデックスを使用していることをEXPLAINが示している場合に便利です。

USE INDEX(index_list)のように動作するFORCE INDEXを使用することもできますが、テーブルスキャンが非常に高価であると想定されます。つまり、テーブルスキャンは、指定されたインデックスの1つを使用してテーブル内の行を検索する方法がない場合にのみ使用されます。

UPDATE

このクエリをお試しください:

SELECT exec_date, 
     100 * SUM(IF(cached = 0, 1, 0))/SUM(1) cached_no, 
     100 * SUM(IF(cached = 1, 1, 0))/SUM(1) cached_yes 
FROM (SELECT exec_date, IF(cached = 'no', 0, 1) cached 
     FROM requests GROUP BY exec_date) AS A 
+1

ありがとう! 'USE INDEX'と' FORCE INDEX'の違いは? – user784637

+1

私の更新された回答を確認してください –

+0

あなたが答えに満足し、それをupvoteそれを受け入れるよりも満足している場合。 –

2

anothe上で一つのインデックスを強制するには、あなたがFORCE INDEXディレクティブ使用することができます:

EXPLAIN SELECT exec_date, 
    100 * SUM(CASE WHEN cached = 'no' THEN 1 ELSE 0 END)/SUM(1) cached_no, 
    100 * SUM(CASE WHEN cached != 'no' THEN 1 ELSE 0 END)/SUM(1) cached_yes FROM requests FORCE INDEX(`is_cached`) GROUP BY exec_date; 

MySQLのオプティマイザはに少ない行を返すインデックスを選択しますあなたのケースでは、この数は両方のインデックス(436695対440493)で非常に近いです。

関連する問題