[英]faster way to use sets in MySQL
我有一個具有以下結構的MySQL 5.1 InnoDB表( customers
):
int record_id (PRIMARY KEY)
int user_id (ALLOW NULL)
varchar[11] postcode (ALLOW NULL)
varchar[30] region (ALLOW NULL)
..
..
..
表格中大約有700萬行。 當前,正在按以下方式查詢表:
SELECT * FROM customers WHERE user_id IN (32343, 45676, 12345, 98765, 66010, ...
在實際查詢中, IN
子句中當前有560個以上的user_id
。 由於表中有幾百萬條記錄,因此此查詢速度很慢 !
表上有二級索引,第一個位於user_id
本身,我認為這會有所幫助。
我知道SELECT(*)
是一件壞事,它將被擴展到所需字段的完整列表。 但是,上面未列出的字段是更多int
和double
。 還有那些被退回的另一個50,但他們需要的報告。
我想有一種更好的方法來訪問user_id
的數據,但是我不知道該怎么做。 我的最初反應是刪除user_id
字段上的ALLOW NULL
,因為我了解NULL
處理會減慢查詢速度?
如果您能指出比使用IN ( )
方法更有效的方向,我將不勝感激。
編輯然解釋,說:
select_type = SIMPLE
table = customers
type = range
possible_keys = userid_idx
key = userid_idx
key_len = 5
ref = (NULL)
rows = 637640
Extra = Using where
有幫助嗎?
首先,檢查USER_ID
上是否有索引, 並確保已使用 。
您可以通過運行EXPLAIN
。
其次,創建一個臨時表並在JOIN
使用它:
CREATE TABLE temptable (user_id INT NOT NULL)
SELECT *
FROM temptable t
JOIN customers c
ON c.user_id = t.user_id
第三,查詢如何返回行?
如果它返回幾乎所有行,那么它將很慢,因為它首先必須通過連接通道泵送所有這幾百萬個數據。
NULL
不會減慢查詢速度,因為IN
條件僅滿足索引的非NULL
值。
更新:
使用索引,該計划是好的,除了它返回超過一百萬行。
您是否真的需要將所有這638,000
行放入報告中?
希望它不會被印出來:對雨林,全球變暖和其他事物有害。
認真地說,您似乎需要對查詢進行聚合或分頁。
“選擇*”並不像某些人想象的那樣糟糕。 基於行的數據庫將提取整行,因此在不使用覆蓋索引的情況下,“ SELECT *”從本質上來講不會比“ SELECT a,b,c”慢(注意:當您有較大的BLOB時,有時是一個例外,但這是一個極端的情況。
首先,您的數據庫是否適合RAM? 如果沒有,請獲取更多的RAM。 不,認真 現在,假設您的數據庫太大而無法合理地放入ram(例如,> 32Gb),那么您應該嘗試減少隨機I / O的數量,因為它們可能會使事情停滯不前。
從這里開始,我假設您正在使用帶有RAID1(或RAID10等)中的RAID控制器和至少兩個主軸的適當服務器級硬件。 如果不是,請離開並獲取該信息。
您絕對可以考慮使用聚集索引。 在MySQL InnoDB中,您只能對主鍵進行集群,這意味着如果當前主鍵有其他內容,則必須對其進行更改。 復合主鍵是可以的,並且如果您要對一個條件(例如user_id)進行大量查詢,則將其設為主鍵的第一部分無疑是有好處的(您需要添加其他內容才能使其成為主鍵)獨特)。
或者,您可以使查詢使用覆蓋索引,在這種情況下,您不需要user_id作為主鍵(實際上,不必這樣)。 僅當您需要的所有列都在以user_id開頭的索引中時,才會發生這種情況。
就查詢效率而言,WHERE user_id IN(大ID列表)幾乎可以肯定是從SQL執行此操作的最有效方法。
但是我最大的提示是:
每次都是一樣的〜560 id嗎? 還是在不同的查詢運行中使用不同的〜500 id?
您可以將560個UserID插入單獨的表(甚至臨時表)中,在該表上粘貼索引,然后將其內部連接到原始表。
這是您最重要的查詢嗎? 這是交易表嗎?
如果是這樣,請嘗試在user_id上創建聚簇索引。 您的查詢可能很慢,因為即使找到匹配的記錄(在user_Id索引上進行索引查找),它仍然必須隨機讀取磁盤以檢索列(鍵查找)。
如果無法更改聚簇索引,則可能需要考慮ETL流程(最簡單的方法是將觸發器插入具有最佳索引的另一個表中)。 這將產生更快的結果。
還要注意,如此大的查詢可能需要一些時間來解析,因此如果可能的話,可以通過將查詢到的ID放入臨時表中來解決問題
您可以嘗試在臨時表中插入需要查詢的ID,並內部聯接兩個表。 我不知道這是否有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.