2017-05-22 76 views
0

清理疑問的話,我做了一個PHP腳本,將產生以下SQL查詢:SQL垃圾收集VS在PHP

SELECT * FROM icecream WHERE 
flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa') 
OR flavor = 'marzipan' AND color = 'purple' AND (quality = 'aaa') 
OR flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa') 

查詢的最後和第一位是相同的。

這看起來我錯了,明明我寧願想運行一個查詢像

SELECT * FROM icecream WHERE 
flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa') 
OR flavor = 'marzipan' AND color = 'purple' AND (quality = 'aaa') 

省略了最後一排。

這看起來很好在這個例子中,但讓我們說, 1.有可能是23「或味道......」部分,而不是 2 100種不同口味 3. 50種不同的顏色 4. 20種不同的質量等級。

突然間,創建一個漂亮的SQL查詢變得複雜得多,而且沒有重複請求相同的數據。

當前的SQL查詢有效。但是,我應該清理查詢以消除重複,還是應該將其留給SQL引擎來爲我做?

我的意思是,我可以做到這一點......但它值得嗎?一方面,我想傳遞乾淨的SQL查詢,但另一方面,這些類似的事情似乎是SQL引擎真正設計的目的。

有什麼建議嗎?

+2

請注意:僅僅因爲'OR'在一個新的行上,它不會使您的SQL段成爲一個單獨的條件。如果沒有括號(( AND/OR )),則評估將是連續的。另外,你可能想看看['IN'運算符](http://www.w3resource.com/mysql/comparision-functions-and-operators/in-function.php) –

+0

當然,我只是爲了可讀性而做到這一點,所以人們很容易看到重複。 我想過使用IN運算符和一個ID使用所有三個不同的部分。 xxxyyzz 其中x =風味,y =顏色,z =質量。 這可能是一個簡單的解決方案,但存在可擴展性問題。如果其中一個值的數量增加到包括一個額外的數字,那麼整個系統需要重新工作。 –

+0

是的,我希望它是連續的。質量='aaa'和質量='aa'的ID會有所不同,所以它是正確的。 另外,因爲可以有100種口味* 50種顏色= 5000種不同的ID,因爲在aaa和aa上沒有使用圓括號,因爲質量可能會膨脹到10000個不同的ID,當我想要的只是2個冰淇淋的ID。 –

回答

2

您可以通過使用EXPLAIN [EXTENDED] SELECT ...來閱讀由MySQL優化器創建的查詢計劃來回答您的問題。如果計劃是相同的,那麼服務器不僅認爲你的查詢在邏輯上是等價的,而且它已經將它們減少到內部相同的查詢。

https://dev.mysql.com/doc/refman/5.7/en/explain.html

你應優先生成的查詢,在邏輯上是最優的,而不是做的事情,可以減少可用的選項,以優化(做不良之類的東西在WHERE使用列名作爲函數的參數,並是眼球調試的。沒有必要爲聰明。

(a = 1 AND b = 1 AND c = 5) OR 
(a = 1 AND b = 1 AND c = 27) 

...是完全等同於...

(a = 1 AND b = 1) AND (c = 5 OR c = 27) 

....或...

(a = 1 AND b = 1 AND c IN (5,27)) 

...和優化器會很容易,無論它們是如何在查詢中表示明白這些條件。由此產生的計劃應該是相同的,因此在生成動態查詢時不需要優先於其他計劃。 (舊版本的MySQL可能不一定已經處理了最後一個,以及他們可能已經處理了前兩個,但現在這應該不是問題)。

重要的是,WHERE當然是一個邏輯表達式,它具有從邏輯的角度來看,確定性評估的優先順序是不確定的,但這與對每一行的評估排序並不相同......理論上,沒有順序來評估最終表達式的條件 - 但優化器是免費到實際上以任何看起來正確和最佳的順序評估條件,無論它們是如何表達的。

根據索引查找,它可能會選擇查找所有b = 1行,然後在該集合中找到c = 5 OR c = 27,最後掃描結果行以查找a = 1條件。如果您在列(b,c)的列上有單個索引,則情況可能如此。在程序上沒有捷徑 - WHERE a = 1 AND b = 1在邏輯上與WHERE b = 1 AND a = 1相同。

請注意,您應該在示例查詢中使用更多括號,以便AND/OR優先級的分組明確無誤。服務器當然會做得對,但眼球更容易受到欺騙,而使眼球明確無誤的圓括號對MySQL優化器不會造成任何損害,似乎這些優化器似乎都喜歡它們。

1

好吧,我看到的問題是:

1)將SQL引擎中刪除重複?

這類事情是什麼的SQL引擎確實是專門做

2)如何我可以通過清潔查詢無需過多努力?

我想通過清潔SQL查詢


SQL是說明性語言。

A declarative language意味着你告訴它該做什麼,它決定了如何去做。

在這種情況下,mysql引擎會接受您的查詢並確定如何檢索您的數據。作爲此過程的一部分,查詢解析器應該刪除查詢中的重複項。 (解析器可能不會刪除它們,這將取決於查詢的複雜性和適當的優化)。這個缺點是稍微長一點的解析,儘管我並不認爲這個延遲很明顯,特別是在一個複雜的查詢中有許多where子句。


看來你的php腳本是專注於低級別的抽象。

我最好的猜測是您的腳本需要一些數據並將其轉換爲字符串,然後通過轉換重複下一部分數據。

該方法的缺點是修改或調整結果對象。轉換器不知道上一步發生了什麼,不能輕鬆檢測並刪除重複的行。你需要做的是有一些對象,可以幫助採取一些規則,並從中建立一個SQL查詢。 (一個這樣的工具是Zend Db)。


最後,我只想說明,您試圖製作的查詢似乎是不必要的複雜。

23「OR味道......」部分

或課程,而這是可能的,你將需要做出這樣一個複雜的查詢,複雜查詢有更多的領域,其中性能會受到影響。審視你試圖完成的事情,並確定是否有更直接的方法來實現它可能更加謹慎。就目前情況而言,我沒有足夠的信息來查看是否有其他方法。