2013-06-27 131 views
0

我有一個表 'TBL' 這樣的事情: ID BIGINT(20) - 主鍵,自動增量 字段1 場2 場3mysql按主鍵選擇順序。性能

這表有60萬個+行。

  1. 查詢: SELECT *從tbl ORDER BY ID LIMIT 600000,1採取1.68秒
  2. 查詢: SELECT ID,FIELD1從tbl ORDER BY ID LIMIT 600000,1採取1.69秒
  3. 查詢:從tbl ORDER SELECT ID由ID LIMIT 600000,1採取0.16秒
  4. 查詢:從tbl SELECT * WHERE ID = XXX取0.005秒

這些查詢在phpmyadmin中進行了測試。

而結果是查詢3和查詢4一起返回數據。 查詢1完成相同的工作,但要慢得多...

這看起來不合適我。 任何人都可以提供任何建議嗎?

P.S.我很抱歉格式化..我是這個網站的新手。

新的測試:

Q5:CREATE TEMPORARY TABLE tmptable AS(SELECT ID FROM tbl WHERE ID LIMIT 600030,30); SELECT * FROM tbl WHERE ID IN(SELECT ID FROM tmptable);需要0.38秒

我仍然不明白它是如何可能的。我重新創建了所有索引...我該怎麼辦這張桌子?手動刪除並重新填充它? :)

回答

3

查詢1查看錶的主鍵索引,在表中找到正確的600,000個ID和它們對應的位置,然後轉到表並從這些600k位置獲取所有內容。

查詢2查看錶的主鍵索引,找到正確的600k ID及其在表內的相應位置,然後轉到表中並從這些600k行中獲取要求的字段子集。

查詢3查看錶的主鍵索引,找到正確的600k ID並返回它們。它根本不需要看錶格。

查詢4查看錶的主鍵索引,查找請求的單個條目,進入表,讀取單個條目並返回它。

時間明智的,讓我們構建向後:

(Q4)表的索引允許在O鍵(id)的查找(log n)的時間,這意味着每個表的規模增加一倍的時間只需要一額外的步驟來找到索引中的鍵*。如果你有100萬行,那麼只需要20步就可以找到它。十億行? 30個步驟。索引條目包括表中要查找該行數據的位置的數據,因此MySQL跳轉到表中的該位置並讀取該行。報告的時間幾乎完全是開銷。

(Q3)正如我所提到的,表格索引非常快,此查詢找到第一個條目,並只遍歷樹直到它具有所請求的行數。我相信我可以計算出需要的步數,但最多我們會說20步×600k行= 12M步;由於它遍歷樹,它可能更像1M步,但確切的數字在很大程度上是不相關的。這裏要實現的最重要的事情是,一旦MySQL走過索引來拉取它所需的ID,它就擁有了你所要求的一切。沒有必要去看桌子。這一次報告的時間本質上是MySQL走索引所需的時間。 (Q2)這與開始討論查詢3時的樹行相同,但是在拉取它所需的ID時,MySQL也將它們在表文件中的位置提取出來。然後它必須轉到表格文件(可能已經在內存中緩存/ mmap),並且對於每個條目,找到表格中的適當位置並從這些行中獲取請求的字段。此查詢報告的時間是行走索引所需的時間(如Q3)以及訪問索引中指定的每一行的時間。

(Q1)當所有字段都被指定時,這與Q2相同。由於時間與Q2基本相同,我們可以看到,從數據庫中提取更多字段的時間並不是真的需要花費更多的時間,任何時候通過爬行索引和尋找行都會導致更多的時間不足。

*:大多數數據庫使用的索引數據結構(MySQL的B-trees)的日誌基數遠遠高於2,這意味着每次該表增加一倍時,而不是每次增加一個額外的步時,桌子尺寸增加了幾百到幾千倍。這意味着,而不是我在示例中所述的20-30步,它更像是2-5。

+0

仍在讀取,但是快速提示:LIMIT 600000,1 - 表示它僅選擇1行起始行600000 – IGonza

+0

錯過了',1'。在這種情況下,1/2和3之間的差別可能是緩存。 4仍然是一個直接查詢,而其他人仍然需要走索引 – Kevin

+0

我在MySQL配置中將現金內存大小設置爲0,所以結果不會被緩存。 – IGonza