簡體   English   中英

相同的查詢,具有限制和排序依據的不同執行計划。 我應該更改索引嗎?

[英]Same query, different execution plan with limit and sort by. Should I change the index?

我有一個包含 1,000,000 條記錄的表。 表看起來像這樣:

CREATE TABLE `items` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `category_id` int(10) unsigned NOT NULL,
  `item_serial` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_index` (`category_id`,`item_serial`),
)

當我執行此查詢時:

select * from `items`
where `category_id` = 1  
order by `id` asc 
limit 22649;

大約需要 0.5 秒,我發現這很長。

如果我執行查詢的解釋,我會得到以下結果:

type | possible_keys  | key            | key_len | ref   | rows  | filtered | Extra
-----|----------------|----------------|---------|-------|-------|----------|-----------------------------------------
ref  | unique_index   | unique_index   | 4       | const | 498253| 100.00   | Using where; Using index; Using filesort

如果我執行完全相同的查詢,但只是從限制中刪除 1 位數字,那么 22648 而不是 22649:

select * from `items`
where `category_id` = 1  
order by `id` asc 
limit 22648;

查詢持續時間要快得多,大約 0.003 秒。

我得到以下結果進行解釋:

type | possible_keys  | key            | key_len | ref   | rows  | filtered | Extra
-----|----------------|----------------|---------|-------|-------|----------|-------------
ref  | unique_index   | PRIMARY        | 8       | null  |  45296| 50.00    | Using where

如您所見,兩個查詢的解釋各不相同,並且查詢持續時間也大不相同。

我還使用了 unique_index 並將 id 列添加到該索引中,將其更改為:

UNIQUE KEY `unique_index` (`id`, `category_id`, `item_serial`),

當我這樣做時,我不再得到不同的結果,但總是使用新索引得到相同的解釋結果,並且快速結果約為 0.003 秒。

所以我有兩個問題:

1 - 為什么具有不同限制的相同查詢會產生不同的執行計划?

2 - 您是否建議將 id 列添加到 unique_index 以獲得更好的性能? 我覺得添加它很奇怪,因為它在唯一性方面沒有意義,因為 id 是自動遞增的並且永遠不會重復,但它確實解決了這種情況下的性能問題。

將不勝感激任何建議。

你發現了一個優化器被撕裂的情況

  • category過濾 -- 覆蓋索引,但需要排序
  • 按順序讀取數據——避免按id順序讀取排序,但必須檢查每一行。

碰巧優化器的硬幣翻轉正好是 22649。明天可能會有所不同——更大更小。

1 (對於category_id )更改為表中的最大值; 時機可能真的很糟糕。

如前所述,以這兩列開頭的索引是最佳的:

INDEX(category_id, id)

注意:InnoDB 將PRIMARY KEY列添加到每個二級索引的末尾。 實際上,該表是兩個 BTree:

(id, category_id, item_serial) -- All the data, in PK order
(category_id, item_serial, id) -- secondary index plus PK

重新 0.003 秒。 -- 這聞起來像是查詢緩存被打開了。 它具有欺騙性。 建議使用SELECT SQL_NO_CACHE ...重新計時SELECT SQL_NO_CACHE ...

你應該改變索引嗎? 好,

UNIQUE KEY `unique_index` (`category_id`,`item_serial`)

既是索引又是唯一性約束。 如果您更改此設置,您將失去唯一性約束。 所以,你堅持添加

INDEX(category_id, id)

暫無
暫無

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

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