簡體   English   中英

在MySQL中使用集的更快方法

[英]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(*)是一件壞事,它將被擴展到所需字段的完整列表。 但是,上面未列出的字段是更多intdouble 還有那些被退回的另一個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執行此操作的最有效方法。

但是我最大的提示是:

  • 牢記目標,找出目標,並在達到目標時停止。
  • 不要相信任何人的話-試試看
  • 確保您的性能測試系統與生產的硬件規格相同
  • 確保性能測試系統的數據大小和種類與生產相同(相同的架構還不夠好!)。
  • 如果無法使用生產數據,則使用合成數據(復制生產數據在邏輯上可能會很困難(請記住您的數據庫> 32Gb);這也可能違反安全策略)。
  • 如果您的查詢是最佳的(可能已經是最佳查詢),請嘗試調整架構,然后調整數據庫本身。

每次都是一樣的〜560 id嗎? 還是在不同的查詢運行中使用不同的〜500 id?

您可以將560個UserID插入單獨的表(甚至臨時表)中,在該表上粘貼索引,然后將其內部連接到原始表。

這是您最重要的查詢嗎? 這是交易表嗎?

如果是這樣,請嘗試在user_id上創建聚簇索引。 您的查詢可能很慢,因為即使找到匹配的記錄(在user_Id索引上進行索引查找),它仍然必須隨機讀取磁盤以檢索列(鍵查找)。

如果無法更改聚簇索引,則可能需要考慮ETL流程(最簡單的方法是將觸發器插入具有最佳索引的另一個表中)。 這將產生更快的結果。

還要注意,如此大的查詢可能需要一些時間來解析,因此如果可能的話,可以通過將查詢到的ID放入臨時表中來解決問題

您可以嘗試在臨時表中插入需要查詢的ID,並內部聯接兩個表。 我不知道這是否有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM