2014-03-03 48 views
1

我目前正在做一些查詢我的應用程序,我需要得到我當前位置上最近的商店,並首先這樣做,我需要得到所有具有同名,然後得到它的信息並修剪掉那個查詢。現在我用語句這一點,但因爲也是基於名單上被搜索的項目,我需要用另外一個選擇的這這裏是我到目前爲止的代碼:更快的搜索查詢IN語句與SELECT中的MySQL

select * 
from product p, 
store s, 
branches b 
where 1 = 1 
and b.idproduct = p.idproduct 
and p.store = s.idstore 
and common_name IN(SELECT p.common_name 
FROM shopping_list_content s, product p 
WHERE 1 =1 
AND s.iditem = p.idproduct 
AND s.idlist =$listid) 

現在的作品,因爲我想它但我希望它比這更快地完成查詢。目前,此查詢運行速度超過此時間需要3秒多。如果它不到一秒鐘,會好得多。我可以使用其他任何選項嗎?

+0

請在您的查詢的解釋,檢查索引,並期待與更換連接中的 –

+0

1 = 1會給所有行 –

+1

爲什麼使用'每個查詢/子查詢中1 = 1'句?如果你有其他人WHERE子句,我錯了嗎? –

回答

2

MySQL有困難的優化子查詢,當你寫類似:

SELECT * 
FROM T 
WHERE T.ID (SELECT ID FROM T2); 

它有時被改寫爲

SELECT * 
FROM T 
WHERE EXISTS 
     ( SELECT 1 
      FROM T2 
      WHERE T.ID = T2.ID 
     ); 

T子查詢然後執行每排一次,而如果你寫:

SELECT T.* 
FROM T 
     INNER JOIN 
     ( SELECT DISTINCT ID 
      FROM T2 
     ) T2 
      ON T2.ID = T.ID; 

你的結果集是一樣的,但MySQL w首先用子查詢的結果填充內存表,並將其散列在T2.ID上,然後只需在T中查找每個行的哈希表。

您想要的行爲取決於您希望從每個表/子查詢得到多少數據。如果T2中有1百萬行,而T中有10個行,那麼填充包含1百萬行的臨時表就沒有意義了,只是隨後只使用它10次,而如果在T中只有大量行在T2少量的實現子查詢的額外成本將是有益的,從長遠來看。

要指出的另一件事(對性能沒有影響),您正在使用的JOIN語法是ANSI 89語法,並在20年前由ANSI 92顯式JOIN語法取代。儘管針對SQL Server,但我認爲this article總結了切換到較新連接語法的原因。進行最終查詢:

SELECT * 
FROM product p, 
     INNER JOIN store s 
      ON p.store = s.idstore 
     INNER JOIN branches b 
      ON b.idproduct = p.idproduct 
     INNER JOIN 
     ( SELECT DISTINCT p.common_name 
      FROM shopping_list_content s 
        INNER JOIN product p 
         ON s.iditem = p.idproduct 
      WHERE s.idlist =$listid 
     ) s 
      ON s.common_name = p.common_name; 

N.B.如果您使用MySQL 5.6.5或更高版本,上述大部分內容不適用。在這個版本中,他們引入了更多Subquery Optimization就解決了很多的上述問題

+0

這真的很不錯!我的意思是說明它是如何被MySQL處理的,而whoa!這個是非常快速的解決方案,它只需要0.0480秒來完成查詢,非常感謝!:D – KaHeL

0

這是您的查詢搞掂使用正確join語法:

select * 
from product p join 
    store s 
    on p.store = s.idstore join 
    branches b 
    on b.idproduct = p.idproduct 
where p.common_name IN (SELECT p.common_name 
         FROM shopping_list_content slc join 
          product p 
          ON slc.iditem = p.idproduct AND 
           slc.idlist = $listid 
         ); 

假設相同common_name不會出現在多個產品shopping_list_content沒有重複的行,你可以用替換此簡單join

select * 
from product p join 
    store s 
    on p.store = s.idstore join 
    branches b 
    on b.idproduct = p.idproduct join 
    shopping_list_content slc 
    on slc.iditem = p.idproduct and 
     slc.idlist = $listid; 

但是,這些假設可能並非如此。在這種情況下,改變子查詢使用exists可以幫助提高性能:

select * 
from product p join 
    store s 
    on p.store = s.idstore join 
    branches b 
    on b.idproduct = p.idproduct 
where exists (SELECT 1 
       FROM shopping_list_content slc join 
        product p2 
        on slc.iditem = p2.idproduct AND 
         slc.idlist = $listid 
       WHERE p.common_name = p2.common_name 
      ); 

對於後一查詢,索引與shopping_list_content(iditem, idlist)沿product(common_name, idproduct)應該有所幫助。