2015-06-20 23 views
1

我在嘗試優化查詢。表中有三種不同的查詢,我認爲這不是必需的。在SQL查詢中使用「AND」和「OR」

這是我想要優化的原始查詢。

SELECT DISTINCT(productid) FROM q_products 
     WHERE visibility=1 and status=0 AND productid IN (productidList) 
     UNION ALL 
     SELECT DISTINCT(q_products.productid) FROM q_products,q_product_apply_access 
     WHERE q_products.productid=q_product_apply_access.productid 
     AND q_product_apply_access.partnerid='partnerid' 
     AND q_product_apply_access.apply_status=0 
     AND q_products.visibility=3 AND q_products.status=0 
     AND q_products.productid IN (productidList) 
     UNION ALL 
     SELECT DISTINCT(q_products.productid) FROM q_products,q_product_aff_access 
     WHERE q_products.productid=q_product_aff_access.productid 
     AND q_product_aff_access.accid='accountid' 
     AND q_products.visibility=2 AND q_products.status=0 
     AND q_products.productid IN (productidList) 

讓我帶大家通過這個查詢,

1)我從q_products具有visibility=1status=0並選擇不同的productid也是productidList

2)我現在選擇不同productidq_products和檢查是否productid是否存在於另一個表q_product_apply_access,如果是,然後檢查q_product_apply_access.partnerid是否與給予我們一樣如果q_product_apply_access.apply_status爲0,然後再次檢查那些productid是否在productidList

3)它做了類似的事情,最後再檢查是否productid s在productidList

我的想法,以優化是是做下列方式 - >

1)選擇所有productidsq_products這是在我的productidList。

2)檢查這些productids是否在表q_product_apply_accessq_product_aff_access中,如果是,則滿足其後續條件。 3)當這一切都完成後,我檢查哪些人有q_products.visibility IN (1,2,3)q_products.status=0

我認爲這樣我可以最小化表中的查找,並且我的查詢將在productidList的最小子集中查詢,該子集可能只包含20-30行。

這是我的代碼,但我沒有得到正確的答案。誰能告訴我我該怎麼做?或者我應該如何在這裏應用嵌套循環?

SELECT DISTINCT(productid) 
     FROM q_products as oc, 
     q_product_apply_access as ocaa, 
     q_product_aff_access as ocfa 
     WHERE productid IN (productidList) 
      AND (
      (oc.productid=ocaa.productid 
      AND ocaa.affiliateid='partnerid' 
      AND ocaa.apply_status=0) 
      OR 
      (oc.productid=ocfa.productid 
      AND ocfa.accid='accountid') 
      ) 
      and status=0 
      AND visibility IN (1,2,3) 
+0

當你說「沒有得到正確答案」時,我假設你的意思是結果不一樣? – brazilianldsjaguar

+0

yup!究竟!加上表格花費更多的時間來查找。 –

+0

所以,如果一個產品的'visibility = 1'是你想要的,不管它在其他表中存在。如果其'visibility = 2',那麼只有在'q_product_aff_access'表中也是如此(不管它是否在另一箇中),並且如果'visibility = 3',那麼你只需要它如果它在'q_product_apply_access'表中還存在。聽起來正確嗎? – brazilianldsjaguar

回答

1

你的問題的標題:

使用 「AND」 和 「OR」 在SQL查詢

可能更準確地定義爲:

使用「AND」和/或「OR」語句可以幫助這個查詢運行得更快嗎?

而且,簡短的回答是, .--優化可能需要在別處完成。

所以,從長遠答案:

在此尋找了一段時間後,「烤成」原始查詢要求防止邏輯JOIN期從加快任何東西。讓這個更快運行的最好方法是利用被引用表上的索引。我原來的答案是使用內部選擇,但沒有達到要求。通過要求,我的意思是必須從productid表中返回一個獨特productid列表滿足三個不同和不同的標準。

這就是說,我會重新寫原來的查詢到更多的東西可讀,使用JOIN語句和別名可讀性(注意沒有DISTINCT - 的UNION確保重複記錄了所有3個結果集)

SELECT p.productid 
FROM q_products p 
WHERE visibility = 1 
    AND status = 0 
    AND productid IN (productIdList) 

UNION 

SELECT p.productid 
FROM q_products p 
JOIN q_product_apply_access paa ON paa.productid = p.productid 
WHERE paa.partnerid = 'partnerid' 
    AND paa.apply_status = 0 
    AND p.visibility = 3 
    AND p.status = 0 
    AND p.productid IN (productidList) 

UNION 

SELECT p.productid 
FROM q_products p 
JOIN q_product_aff_access paf ON paf.productid = p.productid 
WHERE paf.accid = 'accountid' 
    AND p.visibility = 2 
    AND p.status = 0 
    AND p.productid IN (productidList) 

原來的答案

那麼,您遇到的問題是有點困難,因爲它很難總結我的頭周圍原始查詢擺在首位。也就是說,我將內部選擇作爲連接添加到q_products表中,將可能的解決方案放在一起。我沒有測試過,所以讓我知道它是如何證明:

SELECT 
* 
FROM 
    q_products p 
    JOIN (
     SELECT productid FROM q_product_apply_access paa 
     WHERE paa.productid = p.productid 
      AND paa.partnerid = 'partnerid' 
      AND paa.apply_status = 0 
      AND p.visibility = 3 
    ) paa ON paa.productid = p.productid 
    JOIN (
     SELECT productid FROM q_product_aff_access paf 
     WHERE paf.productid = p.productid 
      AND paf.accid = 'accountid' 
      AND p.visibility = 2 
    ) paf ON paf.productid = p.productid 
WHERE 
    p.status = 0 
    AND p.productId IN (productIdList) 
+0

你還沒有在任何地方提到'visibility = 1'條件? –

+0

嗯..你說得對。讓我重新考慮這一點。不幸的是,原始查詢的作用是:1)獲取具有特定標準的產品列表,2)獲取更多不同的標準,3)獲得更多不同的標準,以及4)將它們聯合爲單個結果集。使用'JOIN'返回這樣一個類似的結果集要困難得多,因爲'JOIN'不一定能處理不相關的過濾要求。 – brazilianldsjaguar

+0

UNION ALL不保證唯一性;但是,UNION的三個分支中的不同可見性值確保每個分支中的產品ID都是不相交的集合。 –

0
INDEX(visibility, status, productid) 

與原有UNION ALL

請提供SHOW CREATE TABLE;這可能會提示其他技術。

(編輯)

的事實後,你可以做

ALTER TABLE q_products ADD INDEX(visibility, status, productid); 

這將需要一些時間,這取決於表的大小。

INDEX通常比表本身小得多。

索引是您緩慢查詢的第一道防線。 (重寫是第二次。)

q_products有多大?

+0

我認爲'索引'需要先創建?我無法索引每張桌子,因爲它們已經非常龐大,我無法妥協。 –

0

原始查詢,稍微重新格式化,就是:

SELECT DISTINCT(q_products.productid) 
    FROM q_products 
WHERE q_products.visibility = 1 
    AND q_products.status = 0 
    AND q_products.productid IN (productidList) 
UNION ALL 
SELECT DISTINCT(q_products.productid) 
    FROM q_products, q_product_apply_access 
WHERE q_products.productid = q_product_apply_access.productid 
    AND q_product_apply_access.partnerid = 'partnerid' 
    AND q_product_apply_access.apply_status = 0 
    AND q_products.visibility = 3 
    AND q_products.status = 0 
    AND q_products.productid IN (productidList) 
UNION ALL 
SELECT DISTINCT(q_products.productid) 
    FROM q_products, q_product_aff_access 
WHERE q_products.productid = q_product_aff_access.productid 
    AND q_product_aff_access.accid = 'accountid' 
    AND q_products.visibility = 2 
    AND q_products.status = 0 
    AND q_products.productid IN (productidList) 

你沒有告訴我們是否有任何其他值visibility以外123所以我們必須假設可能也有其它值(但請注意此答案下面的評論)。

我們可以看到,有一些共同的子表達式從q_productsstatus = 0productid IN (productidList),它是不明確的限制行什麼productidList真的是,但我們可以假設它的工作原理確定。

這將是如果MySQL不得不爲支持的CTE(公共表表達式,又名WITH子句)真的有用:

WITH pv AS 
    (SELECT productid, visibility 
     FROM q_products 
     WHERE status = 0 
     AND visibility IN (1, 2, 3) -- or visibility >= 1 and visibility <= 3 
     AND productid IN (productidList) 
    ) 
SELECT pv.productid 
    FROM pv 
WHERE pv.visibility = 1 
UNION ALL 
SELECT DISTINCT(pv.productid) 
    FROM pv 
    JOIN q_product_apply_access AS a 
    ON pv.productid = a.productid 
WHERE pv.visibility = 3 
    AND a.apply_status = 0 
    AND a.partnerid = 'partnerid' 
UNION ALL 
SELECT DISTINCT(pv.productid) 
    FROM pv 
    JOIN q_product_aff_access AS f 
    ON pv.productiond = f.productid 
WHERE pv.visibility = 2 
    AND f.accid = 'accountid' 

從MySQL還不支持CTE的,你可能有寫的CTE出來逐字3次,並希望優化器發現你正在做的事情。或者,由於所有的選擇都是關於更準確地過濾的知名度,您在CTE的改良形式,使得短期(和避免選擇visibility明確),並寫了三次 - 這樣的:

SELECT pv.productid 
    FROM (SELECT productid 
      FROM q_products 
     WHERE status = 0 
      AND visibility = 1 
      AND productid IN (productidList) 
     ) AS pv 
UNION ALL 
SELECT DISTINCT(pv.productid) 
    FROM (SELECT productid 
      FROM q_products 
     WHERE status = 0 
      AND visibility = 3 
      AND productid IN (productidList) 
     ) AS pv 
    JOIN q_product_apply_access AS a 
    ON pv.productid = a.productid 
WHERE a.apply_status = 0 
    AND a.partnerid = 'partnerid' 
UNION ALL 
SELECT DISTINCT(pv.productid) 
    FROM (SELECT productid 
      FROM q_products 
     WHERE status = 0 
      AND visibility = 2 
      AND productid IN (productidList) 
     ) AS pv 
    JOIN q_product_aff_access AS f 
    ON pv.productiond = f.productid 
WHERE f.accid = 'accountid' 

這應該會產生相同的結果。很難確定它會更快。這可能取決於q_products的狀態和可見性列是否有適當的索引。 UNION的第一個術語可以寫得更簡單,但是這個表達與其他兩個備選方案是一致的,這使得這些事情更加清晰(對於閱讀查詢的人來說,也可能使查詢優化器也如此)。

一如既往,研究實際的查詢計劃可能會幫助您改進工作。

+0

'visibility'是一個'enum'對象,其值只有'1,2和3',而productidlist是一個由productids –

+0

OK組成的數組。今後不要留下那些沒有你的問題的細節。這對我的回答沒有太大的影響。它只是簡單地將CTE中的'AND visibility IN(1,2,3)'術語渲染爲多餘的(但是查詢優化器可能會發現這一點,而不用擔心如果它知道它始終是真實的,那麼就不用擔心測試條件 - 沒有空值來處理, 例如)。我對'productidList'更加好奇,這是什麼意思。 –