簡體   English   中英

優化大型MySQL表中的索引

[英]Optimizing an index in a large MySQL table

我有一個大表(大約3百萬條記錄),主要包括以下字段:rowID(int),deviceID(varchar(20)),格式為1536169459(int(10))的UnixTimestamp,具有整數的powerLevel范圍介於30到90(smallint(6))之間。

我正在尋找在特定時間范圍內(使用UnixTimestamp)針對特定deviceID以及powerLevel高於特定數字的記錄。 擁有超過300萬條記錄,需要一段時間。 有沒有一種方法可以創建為此優化的索引?

在以下位置創建索引:

DeviceId,
PowerLevel,
UnixTimestamp

選擇時,您將首先縮小給定設備的記錄集,然后將其縮小到僅在正確PowerLevel范圍內的那些記錄。 最后,對於每個PowerLevel,它將通過UnixTimestamp縮小到正確的記錄。

如果我對您的理解正確,則希望加快此類查詢的速度。

SELECT something
  FROM tbl
 WHERE deviceID = constant
   AND start <= UnixTimestamp
   AND UnixTimestamp < end
   AND Power >= constant

您有一個常量條件(deviceID)和兩個范圍標准(UnixTimestamp和Power)。 MySQL的索引是BTREE(按順序排序),MySQL只能對SELECT進行一次索引范圍掃描。

因此,您可能應該在(deviceID, UnixTimestamp, Power)上選擇一個索引。 為了滿足該查詢,MySQL將隨機訪問設備ID條目的索引,然后進一步隨機訪問滿足UnixTimestamp起始條件的第一行。

然后它將順序掃描索引,並使用每個索引條目中的Power信息來決定是否應選擇每一行。

您也可以使用(deviceID, Power, UnixTimestamp) 但是在這種情況下,MySQL將找到匹配設備和電源標准的第一個條目,然后掃描索引以查看所有時間戳記的條目,以查看應選擇的行。

您的性能目標是讓MySQL掃描盡可能少的索引條目,因此(deviceID, UnixTimestamp, Power)選擇似乎很有可能是更好的選擇。 UnixTimestamp上的索引列可能比Power上的索引列更具選擇性 (這是我的猜測。)

ALTER TABLE tbl CREATE INDEX tbl_dev_ts_pwr (deviceID, UnixTimestamp, Power);

查看Bill Karwin的教程。 另請參閱Markus Winand的https://use-the-index-luke.com

建議的三列索引僅部分有用。 優化程序將使用前兩列,但忽略第三列。

更好:

INDEX(DeviceId, PowerLevel),
INDEX(DeviceId, UnixTimestamp)

為什么?

優化器將在這兩者之間進行選擇,這似乎更具選擇性。 如果時間范圍為“ narrow”,則將使用第二個索引; 如果沒有很多具有所需PowerLevel的行,則將使用第一個索引。

更好的...

PRIMARY KEY ...您可能已將Id作為PK? 也許(DeviceId, UnixTimestamp)是唯一的? (或者您可以在一秒鍾內獲得單個設備的兩個讀數嗎?)如果該對是唯一的,請完全擺脫Id並獲得

PRIMARY KEY(DeviceId, UnixTimestamp),
INDEX(DeviceId, PowerLevel)

筆記:

  • 擺脫Id可以節省空間,從而提供一點速度。
  • 當使用二級索引時,執行程序會花費一些時間在索引的BTree和數據BTree之間(由PK排序)。 通過具有PRIMARY KEY(Id) ,可以確保執行彈跳。 通過將PK更改為此,可以避免跳動。 可能會使查詢速度加倍。
  • (我不確定二級索引是否將全部使用。)

另一個(次要)建議:標准化DeviceId ,以使其(可能)是2字節的SMALLINT UNSIGNED (范圍為0..64K)而不是VARCHAR(20) 即使需要JOIN ,查詢也會運行得更快。 並且節省了大量空間。

暫無
暫無

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

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