[英]Create a MYSQL index for where clause and order_by
考慮到這張表,
CREATE TABLE tbl_tax (
taxdata_id int(11) NOT NULL AUTO_INCREMENT,
tax_year varchar(255) NOT NULL,
display_pid varchar(255) NOT NULL,
type varchar(255) NOT NULL,
tax_id varchar(255) NOT NULL,
tax_amount varchar(255) NOT NULL,
total_due varchar(255) NOT NULL,
paid_wcert varchar(255) NOT NULL,
datelast_adv varchar(255) NOT NULL,
pmtmade_today varchar(255) NOT NULL,
owner_name varchar(255) NOT NULL,
PRIMARY KEY (taxdata_id),
UNIQUE KEY unique_tbl_tax_TaxidYear (tax_id,tax_year),
KEY tax_year_2 (tax_year, owner_name, tax_id, display_pid,
type, tax_amount, total_due, total_paid, datelast_adv, pmtmade_today,
taxdata_id, paid_wcert)
) ENGINE=InnoDB AUTO_INCREMENT=100000 DEFAULT CHARSET=latin1;
tbl_tax;
考慮到這個 SQL 查詢,
SELECT tax_year
, tax_id
, owner_name
, display_pid
, type
, tax_amount
, total_due
, total_paid
, datelast_adv
, pmtmade_today
, taxdata_id
, paid_wcert
FROM tbl_tax
WHERE tax_year >= '2015'
AND tax_year <= '2019'
ORDER
BY tax_year DESC;
我想創建一個索引並嘗試創建一個封面索引。
引用這篇文章,“一般規則是首先選擇要過濾的列(具有相等條件的 WHERE 子句),然后是排序/分組(ORDER BY 和 GROUP BY 子句),最后是數據投影(SELECT 子句)。”
ALTER TABLE tbl_tax
ADD INDEX (
`tax_year`, `owner_name`, `tax_id`, `display_pid`,
`type`, `tax_amount`, `total_due`, `total_paid`, `datelast_adv`, `pmtmade_today`,
`taxdata_id`, `paid_wcert`
);
做一個explain
,顯示,
"id" : 1,
"select_type" : "SIMPLE",
"table" : "tbl_tax",
"partitions" : null,
"type" : "index",
"possible_keys" : "tax_year_2",
"key" : "tax_year_2",
"key_len" : "2831",
"ref" : null,
"rows" : 271630,
"filtered" : 50.00,
"Extra" : "Using where; Backward index scan; Using index"
在創建索引時,我知道:-
這些可能是explain
的 output 顯示"rows": 271630,
但是,SQL 查詢的結果集只有 ~2000 行。
嘗試閱讀許多文章,但我仍在努力優化它。
我該怎么做才能獲得更好的優化? 我可以用更好的方式創建索引嗎? 我可以對 SQL 查詢進行任何更改嗎? 另外,如果我在這里誤解了什么,請隨時糾正我。
這是一個有趣的案例,因為通常我們希望在 EXPLAIN 計划中看到Using index
,但在這種情況下這是一種損害。
原因是這是type: index
,這意味着它正在進行索引掃描。 這意味着它正在掃描整個索引,而不僅僅是符合您條件的行。 這就是它顯示rows: 271630
的原因。 這基本上就是您的表的大小(或者至少是優化器根據其統計信息估計的表的大小)。
在這種情況下,我認為將每一列添加到索引中沒有幫助。 使用一列的索引會更好: tax_year
。
然后我希望 EXPLAIN 顯示type: range
因為你的條件,這表明它正在檢查的唯一行是那些匹配條件的行。
然后我們會看到Filtered: 100.00
這表明所有檢查的行都包含在結果中,這很好。 這意味着查詢是有效的,因為沒有行被檢查但隨后被過濾掉。
此外,由於您的 ORDER BY 是針對同一列的,因此我仍然希望Using filesort
不存在,這很好。
回復您的評論:
我想您在 2015 年至 2019 年之間的 tax_year 條件與表的很大一部分相匹配。 如果您的條件匹配大部分行,MySQL 選擇不使用索引。 它估計使用索引比只掃描表的成本更高。
如果你認為優化器做出了錯誤的選擇,你可以給它一個提示,應該假定表掃描的成本更高:
... FROM tbl_tax FORCE INDEX(tax_year) ...
(我假設索引的名稱是tax_year
,但你應該用你的情況下的索引名稱替換它。)
我也同意其他人的觀點,即您對每個屬性列使用varchar(255)
是不合適的。
INDEX(tax_year, ...)
確實處理WHERE
和ORDER BY
。
查詢包含 ORDER_BY 的順序與訪問行的順序不同。
錯誤的。 WHERE
沒有指定訪問它們的順序。 實際上EXPLAIN
說的是“向后索引掃描”。 一切都很好。
使用合理的數據類型,例如tax_year
的 2 字節YEAR
而不是VARCHAR(255)
,它需要 6 個字節來表示一年。
varchars 的算術(“數量”等)會很混亂。
當然,“覆蓋”索引有一點幫助。 但我不喜歡讓索引大於 5 列。 你的大索引有助於查詢一些,但也會傷害一些INSERTs
。
(我同意比爾的觀點。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.