[英]Indexed column and not indexed column research
我生成了單獨的 MySQL Innodb 表,其中包含 2000、5000、10000、50000、10000、20000、50000、100 000、200 000 個元素(借助 php 循環和插入查詢)。 每個表有兩列:id(Primary Key INT autoincrement)、number(INT UNIQUE KEY)。 然后我做了同樣的但這次我生成了類似的表,其中number列沒有 INDEX 。我以這樣的方式生成表:列號的值等於索引值 + 2:第一個元素 == 3,第 1000 個元素是 1002,依此類推。 我想測試這樣的查詢,因為它將在我的應用程序中使用:
SELECT count(number) FROM number_two_hundred_I WHERE number=200002;
在為這些表生成數據后,我想測試最壞情況查詢的時間。 我使用了顯示配置文件。 我假設最壞情況的查詢將對應於列號值為 1002、2002 等的元素,所以這里是我測試的所有查詢和時間(由 SHOW PROFILES 評估):
SELECT count(number) FROM number_two_thousand_I WHERE number=2002;
// for tables with indexed column number I used **suffix _I** in the end
// of name of the table. Here is the time for it 0.00099250
SELECT count(number) FROM number_two_thousand WHERE number=2002;
// column number is not indexed when there is no **suffix _I**
// time for this one is 0.00226275
SELECT count(number) FROM number_five_thousand_I WHERE number=5002;
// 0.00095600
SELECT count(number) FROM number_five_thousand WHERE number=5002;
// 0.00404125
結果如下:
2000 el - 索引 0.00099250 未索引 - 0.00226275
5000 el - 索引 0.00095600 未索引 - 0.00404125
10000 el - 索引 0.00156900 未索引 - 0.00761750
這是信息圖。 它顯示了元素數量如何取決於索引/未索引列的最壞情況查詢時間。 索引是紅色。 當我測試速度時,我在 mysql 控制台中輸入了 2 次相同的查詢,因為我發現當您第一次進行查詢時,有時查詢未索引列甚至比索引列還要快一點。 問題是:為什么這種對 200000 個元素的查詢有時比對列號進行索引時對 100000 個元素的相同查詢花費的時間更少。 你可以看到還有其他對我來說不可預測的結果。 我問這個,因為當列號沒有被索引時,結果是可以預測的:200000 el 時間總是大於 100000。請告訴我在嘗試對 UNIQUE 索引列進行研究時我做錯了什么。
在未索引的情況下,它始終是全表掃描,因此時間與行號很好地吻合,如果它被索引,您正在測量索引查找時間,這在您的情況下是恆定的(小數字,小偏差)
這還不是“最壞”的情況。
UNIQUE
密鑰隨機而不是與 PK 處於鎖定步驟。 這樣的一個例子是UUID()
。如果兩者兼而有之,您最終會看到性能顯着下降。
UNIQUE
鍵對INSERTs
有以下影響:在返回給客戶端之前檢查唯一性約束。 對於非 UNIQUE 索引,插入索引的 BTree 的工作可以(並且已經)延遲。 (參見“更改緩沖區”)。由於第二列上沒有索引,因此要做的工作更少。
WHERE number=2002
--
UNIQUE(number)
-- 深入 BTree。 非常快,非常有效率。INDEX(number)
-- 深入 BTree。 非常快,非常有效率。 但是它稍微慢一些,因為它不能假設只有一個這樣的行。 也就是說,在 BTree 中找到正確的位置后,它將向前掃描(非常有效),直到找到 2002 以外的值。number
索引——掃描整個表。 所以成本取決於表的大小,而不是number
的值。 它不知道 2002 是否存在於表中的任何位置,或者存在多少次。 如果你繪制你得到的時間,你會發現它是相當線性的。 我建議您在圖表中使用 log-log 'paper'。 無論如何,請注意非索引情況的線性程度。 並且索引的情況基本上是恆定的。 查找 number=200002 與查找 number=2002 一樣便宜。 這適用於UNIQUE
和INDEX
。 (實際上,由於 BTree 確實是 O(log n),而不是 O(1),因此行中有非常小的上升。對於 2K 行,BTree 中可能有 2 個級別;對於 200K,則為 3 個級別。)
查詢緩存可以在時間上絆倒您(如果它已打開)。 計時時,請執行SELECT SQL_NO_CACHE ...
以避免 QC。 如果 QC 開啟並應用,那么相同查詢的第二次和后續運行將花費非常接近 0.000 秒。
那些在 0.5 毫秒和 1.2 毫秒之間變化的時間 - 將其歸結為月相。 說真的,任何低於 10 毫秒的時間都不應該被信任。 這是因為計算機上可能同時發生的所有其他事情。 您可以通過平均多次運行來稍微調整它——確保避免 (1) 查詢緩存和 (2) I/O。
至於 I/O...這又回到了我之前關於當表(和/或索引)大於 RAM 中緩存時可能發生的情況的評論。
從技術上講,您的標簽不正確。 MySQL的索引大多是BTrees(實際上是B+Trees),而不是二叉樹。 (當然,有很多相似之處,許多原則是共享的。)
回到你的研究目標。
執行任何SELECT
的主要成本是它接觸了多少行。
UNIQUE
索引,它觸及 1 行。 所以期待快速和 O(1) (加上噪音)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.