2011-05-30 67 views
3
EXPLAIN SELECT * 
FROM (
`phppos_items` 
) 
WHERE (
name LIKE 'AB10LA2%' 
OR item_number LIKE 'AB10LA2%' 
OR category LIKE 'AB10LA2%' 
) 
AND deleted =0 
ORDER BY `name` ASC 
LIMIT 16 

+----+-------------+--------------+-------+-----------------------------------+------+---------+------+------+-------------+ 
| id | select_type | table  | type | possible_keys      | key | key_len | ref | rows | Extra  | 
+----+-------------+--------------+-------+-----------------------------------+------+---------+------+------+-------------+ 
| 1 | SIMPLE  | phppos_items | index | item_number,name,category,deleted | name | 257  | NULL | 32 | Using where | 
+----+-------------+--------------+-------+-----------------------------------+------+---------+------+------+-------------+ 

該查詢需要9秒才能運行(該表有100萬行+)。我是否需要有一個多列索引?

我有一個item_number,名稱,類別的索引,單獨刪除。我怎樣才能加快這個查詢?

回答

3

最好我知道,MySQL不知道如何執行位圖或索引掃描。但是如果你在每個領域都有一個索引,你可以將它重寫爲三個查詢的聯合來強制它做這樣的事情。如果是這樣,這將是非常快的:

select * 
from (
    select * from (
      select * 
      from phppos_items 
      where name like 'AB10LA2%' and deleted = 0 
      order by `name` limit 16 
      ) t 
    union 
    select * from (
      select * 
      from phppos_items 
      where item_number like 'AB10LA2%' and deleted = 0 
      order by `name` limit 16 
      ) t 
    union 
    select * from (
      select * 
      from phppos_items 
      where category like 'AB10LA2%' and deleted = 0 
      order by `name` limit 16 
      ) t 
) as top rows 
order by `name` limit 16 
+0

不錯...應該檢查三次排列這個巨大的表格實際上是一個好主意...雖然...可能工作... – 2011-05-30 15:37:49

+0

如果MySQL執行此操作對,它會在應用聯合之前排序每個子集。相比之下,你的建議將需要對每個字段的每個子集進行排序(因爲'union'子句將需要去除唯一字符串)。換句話說,排序以任何一種方式發生;這個版本會在訂購之前取得前n行。 – 2011-05-30 15:41:57

+0

你可能是對的。這大概是最好的解決方案。這是一個非常好的主意,+1 – 2011-05-30 15:44:45

1

OR運營商可能會對執行計劃產生毒害。你可以嘗試重新短語查詢由具有同等UNION更換OR條款:

SELECT * 
FROM (
    SELECT * FROM `phppos_items` 
    WHERE name LIKE 'AB10LA2%' 
    UNION 
    SELECT * FROM `phppos_items` 
    WHERE item_number LIKE 'AB10LA2%' 
    UNION 
    SELECT * FROM `phppos_items` 
    WHERE category LIKE 'AB10LA2%' 
) 
WHERE deleted =0 
ORDER BY `name` ASC 
LIMIT 16 

這將使MySQL來應用UNION操作到每個子查詢結果之前,並行運行幾個子查詢。我知道這對Oracle有很大的幫助。也許MySQL可以做類似的事情?注:我假設LIKE 'AB10LA2%'是一個非常有選擇性的過濾器。否則,由於延遲訂購和限制執行計劃,這可能無法改進。請參閱Denis's答案以獲得更一般的方法。

在任何情況下,我認爲多列索引不會幫助您,因爲您的搜索表達式中有'%'符號。這樣,只有多列索引中的第一列可以使用,其餘的仍然需要索引掃描或全表掃描。

+0

我會給這個嘗試,這聽起來像一個好主意。 – 2011-05-30 15:32:39

+0

這是正確的,但它會導致獲取所有行並對它們進行排序。 – 2011-05-30 15:33:16

+0

@Denis:好點,但我認爲AB10LA2%過濾器有足夠的選擇性來忽略這個事實 – 2011-05-30 15:34:38

相關問題