2012-11-26 17 views
5

如果我創建以下兩個indicies創建索引的順序會影響查詢優化程序將選擇哪個索引?

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輸出是以下

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  

我有以下查詢

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 

不過,我想強制查詢優化器使用is_cached索引而不是daily_ips索引。

如果我刪除daily_ips指數,然後重新添加

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

然後運行相同的EXPLAIN語句,查詢優化器選擇的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條件進行計數。 (雖然緩存必須是索引中的第一個鍵)。基本上,CASE會導致您執行表掃描。 – Corbin

+1

我已經更新了我的答案檢查 –

+0

@Corbin我不確定我瞭解如何執行查詢。我怎樣才能將查詢重組爲2個查詢(任何示例代碼將不勝感激)? – user784637

回答

2

您可以指定查詢運行哪個索引sholud。

試試這個:和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 USE INDEX(is_cached) 
GROUP BY exec_date; 

Differnce之間USE INDEX

通過指定USE INDEX(索引 - 目錄),你可以告訴MySQL只使用指定的指標之一查找表中的行。替代語法IGNORE INDEX(index_list)可用於告訴MySQL不使用某些特定的索引或索引。如果EXPLAIN顯示MySQL正在使用可能索引列表中的錯誤索引,那麼這些提示非常有用。

您也可以使用FORCE INDEX,它的作用與USE INDEX(index_list)相似,但另外假設表掃描非常昂貴。換句話說,只有在無法使用某個給定索引來查找表中的行時才使用表掃描。

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

如果您對答案感到滿意,那麼請接受答案並加以滿意。 –

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 vs 440493)。