2016-08-13 93 views
-4

可憐我有一個非常簡單的表有三列:MySQL的 - 在選擇業績從一個簡單的表格

- A BigINT, 
- Another BigINT, 
- A string. 

前兩列被定義爲索引,也沒有重複。而且,這兩列的價值都在增長。

該表有近400K條記錄。

我需要選擇字符串時的值是內的那些塔1和兩個,爲了詞:

SELECT MyString 
    FROM MyTable 
WHERE Col_1  <= Test_Value 
    AND Test_Value <= Col_2  ; 

結果可以是找不到或單個值。

查詢需要幾乎整整一秒的時間,而直覺上(想象一個數組中的二進制搜索),它應該只需要一小段時間。

我檢查了索引類型,它是兩列(1和2)的BTREE。

任何想法如何提高性能?

在此先感謝。

編輯: 的解釋如下:

選擇類型:簡單, 類型:範圍, 可能的關鍵字:PRIMARY 重點:小學, 密鑰長度:8, 行:441, 已過濾:33.33 , 額外:使用where。

+3

有複合索引? – YOU

+0

在尋求績效建議時,有必要展示確切的表格結構和索引。使用EXPLAIN命令來讓查詢計劃者描述它正在做什麼也是有幫助的。請[編輯]您的問題以包含這些項目。 –

+0

沒有複合索引@YOU。 – FDavidov

回答

2

如果我正確理解你的混淆,你有一個startend的值,例如一對列中的日期時間或IP地址?你想看看你的給定的日期時間/ IP是否在給定的範圍內?

那麼,沒有辦法在這樣的表上一般地優化這樣的查詢。優化器不知道給定的值是否可以在多個範圍內。或換句話說,範圍是否不相交。

因此,優化器最好使用從startend開始的索引,並掃描一半的表格。效率不高。

範圍是否重疊? IP Addresses

對結果有什麼看法?也許這樣的一個kludge將工作:SELECT ... WHERE Col_1 <= Test_Value ORDER BY Col_1 DESC LIMIT 1

+0

謝謝@RickJames的回答。添加'ORDER'和'LIMIT'會產生很大的不同,需要進一步的測試,當達到最終結果時會更新,按照IP地址,不是,但是很像。 – FDavidov

1

您的查詢,用較短的標識符改寫,這是

SELECT s FROM t WHERE t.low <= v AND v <= t.high 

要使用索引會是這樣的滿足這個查詢:首先,我們必須尋找到符合第一這些標準

所有行的表或索引
t.low <= v 

我們可以認爲這是BTREE索引的半掃描。它從一開始就開始,到達v時停止。

它需要在的另一個半掃描以滿足v <= t.high。然後它需要合併兩個結果集來確定符合兩個條件的行。問題是,合併的兩個結果集很大,並且幾乎完全不重疊。

因此,查詢計劃員可能應該選擇全表掃描來代替您的條件。在MySQL中,查詢規劃人員不擅長使用多個索引的情況尤其如此。

您可以或不可以通過(low, high, s)上的複合索引加速此確切查詢 - 原始列名爲(Col_1, Col_2, MyString)。這被稱爲covering index,並允許MySQL完全從索引中滿足查詢。它有時有助於表現。 (如果您的表格的確切定義可用,那麼猜測這是否會有所幫助;覆蓋索引的效率取決於其他索引,主鍵,列大小等內容,但您已選擇最少的公開內容)

這真的會有幫助嗎?反思你的算法可以爲你帶來很多好處。您似乎試圖檢索測試點v位於[t.low,t.high]範圍內的行。您的應用程序是否提供了範圍寬度的先驗限制?也就是說,有沒有已知的最大值t.high - t.low?如果是這樣,我們稱之爲maxrange。然後,你可以重寫查詢是這樣的:

SELECT s 
    FROM t 
    WHERE t.low BETWEEN v-maxrange AND v 
    AND t.low <= v AND v <= t.high 

maxrange可用,我們可以添加col BETWEEN const1 AND const2條款。這將變成對low上索引的有效範圍掃描。在那種情況下,上面提到的覆蓋指數肯定會加速這個查詢。

閱讀此項。 http://use-the-index-luke.com/

+0

非常感謝@OllieJones或the詳細的解釋(以及花費的時間)!一些評論:1)我沒有隱藏信息。該表格完全符合**的描述(兩個BigInt列和前兩列有索引的字符串); 2)不幸的是,最大和最小值之間沒有預定義的範圍(即't.high - t.low'); 3)測試值'v'是一個隨機生成的數字。 – FDavidov

0

嗯......我找到了一個合適的解決方案(不確定你的傢伙會喜歡它,但據說,它適用於我)。

我簡單地分我的400K記錄成多個表,並創建了一個簡單的表用作選擇器:

選擇器表用一個簡單的索引一起保持所述第一列的每個分區的極小值(即1,2,...)。

我那麼用戶下面來獲取應該包含搜索到的範圍,如表的索引:

SELECT Table_Index 
    FROM tbl_selector 
WHERE start_range <= Test_Val 
ORDER BY start_range DESC LIMIT 1 ; 

這會給我,我想從選擇表的索引。

然後我在檢索的索引上有一個CASE來選擇正確的分區表來執行實際的搜索。 (我想更優雅的是使用動態SQL,但稍後會照顧;現在只是想測試方法)。

結果是我得到的響應遠低於第二個(〜0.08),並且它是統一的,不管用於測試的數量。順便說一句,以前的方法並不是這樣:在那裏,如果數字「接近」表的開頭,則結果產生得相當快;另一方面,如果記錄接近表格末尾,則需要幾秒鐘才能完成)。

[順便說一句,我想你明白我的意思開始表結束]

同樣,我敢肯定,人們可能不喜歡這一點,但它的工作對我來說。

謝謝大家的努力協助!