簡體   English   中英

為where子句和order_by創建MYSQL索引

[英]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"   

在創建索引時,我知道:-

  1. WHERE 子句包括范圍謂詞 (<=, >=)
  2. 查詢包含 ORDER_BY 的順序與訪問行的順序不同。

這些可能是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, ...)確實處理WHEREORDER BY

查詢包含 ORDER_BY 的順序與訪問行的順序不同。

錯誤的。 WHERE沒有指定訪問它們的順序。 實際上EXPLAIN說的是“向后索引掃描”。 一切都很好。

使用合理的數據類型,例如tax_year的 2 字節YEAR而不是VARCHAR(255) ,它需要 6 個字節來表示一年。

varchars 的算術(“數量”等)會很混亂。

當然,“覆蓋”索引有一點幫助。 但我不喜歡讓索引大於 5 列。 你的大索引有助於查詢一些,但也會傷害一些INSERTs

(我同意比爾的觀點。)

暫無
暫無

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

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