1. 程式人生 > >[慢查優化]建索引時注意欄位選擇性 & 範圍查詢注意組合索引的欄位順序

[慢查優化]建索引時注意欄位選擇性 & 範圍查詢注意組合索引的欄位順序

文章轉自:http://www.cnblogs.com/zhengyun_ustc/p/slowquery2.html
寫在前面的話:
之前曾說過“不要求每個人一定理解 聯表查詢(join/left join/inner join等)時的mysql運算過程”,但對於欄位選擇性差意味著什麼,組合索引欄位順序意味著什麼,要求每個人必須瞭解;
重複上一次的話:把mysql客戶端(如SQLyog,如HeidiSQL)放在桌面上,時不時拿出來 explain 一把,這是一種美德!
確保親手查過SQL的執行計劃,一定要注意看執行計劃裡的 possible_keys、key和rows這三個值,讓影響行數儘量少,保證使用到正確的索引,減少不必要的Using temporary/Using filesort;
不要在選擇性非常差的欄位上建索引,原因參見優化策略A;
查詢條件裡出現範圍查詢(如A>7,A in (2,3))時,要警惕,不要建了組合索引卻完全用不上,原因參見優化策略B;
我們先回顧一下欄位選擇性的基礎知識。
——欄位選擇性的基礎知識——

引子:什麼欄位都可以建索引嗎?

如下表所示,sort 欄位的選擇性非常差,你可以執行 show index from ads 命令可以看到 sort 的 Cardinality(雜湊程度)只有 9,這種欄位上本不應該建索引:

Table

Non_unique

Key_name

Seq_in_index

Column_name

Collation

Cardinality

Sub_part

Packed

Null

Index_type

Comment

ads

1

sort

1

sort

A

9

\N

\N

BTREE

優化策略A:欄位選擇性
選擇性較低索引 可能帶來的效能問題
索引選擇性=索引列唯一值/表記錄數;
選擇性越高索引檢索價值越高,消耗系統資源越少;選擇性越低索引檢索價值越低,消耗系統資源越多;
查詢條件含有多個欄位時,不要在選擇性很低欄位上建立索引
可通過建立組合索引來增強低欄位選擇性和避免選擇性很低欄位建立索引帶來副作用;
儘量減少possible_keys,正確索引會提高sql查詢速度,過多索引會增加優化器選擇索引的代價,不要濫用索引;
再回顧組合索引與範圍查詢的業務場景。
——組合索引欄位順序與範圍查詢之間的關係——

引子:範圍查詢 city_id in (0,8,10) 能用組合索引 (ads_id,city_id) 嗎?

舉例,

ac 表有一個組合索引(ads_id,city_id)。

那麼如下 ac.city_id IN (0, 8005) 查詢條件能用到 ac表的組合索引(ads_id,city_id) 嗎?

EXPLAIN

SELECT ac.ads_id

FROM ads, ac

WHERE

  ads.id = ac.ads_id

  AND ac.city_id IN (0, 8005) 

  AND ads.status = 'online'

  AND ac.start_time<UNIX_TIMESTAMP()

  AND ac.end_time>UNIX_TIMESTAMP()

優化策略B:

由於 mysql 索引是基於 B-Tree 的,所以組合索引有“欄位順序”概念。

所以,查詢條件中有 ac.city_id IN (0, 8005),而組合索引是 (ads_id,city_id),則該查詢無法使用到這個組合索引。

DBA總結道:

組合索引查詢的各種場景
茲有 Index (A,B,C) ——組合索引多欄位是有序的,並且是個完整的BTree 索引。
下面條件可以用上該組合索引查詢:
A>5
A=5 AND B>6
A=5 AND B=6 AND C=7
A=5 AND B IN (2,3) AND C>5
下面條件將不能用上組合索引查詢:
B>5 ——查詢條件不包含組合索引首列欄位
B=6 AND C=7 ——查詢條件不包含組合索引首列欄位
下面條件將能用上部分組合索引查詢:
A>5 AND B=2 ——當範圍查詢使用第一列,查詢條件僅僅能使用第一列
A=5 AND B>6 AND C=2 ——範圍查詢使用第二列,查詢條件僅僅能使用前二列

組合索引排序的各種場景
茲有組合索引 Index(A,B)。
下面條件可以用上組合索引排序:

ORDER BY A——首列排序
A=5 ORDER BY B——第一列過濾後第二列排序
ORDER BY A DESC, B DESC——注意,此時兩列以相同順序排序
A>5 ORDER BY A——資料檢索和排序都在第一列
下面條件不能用上組合索引排序:
ORDER BY B ——排序在索引的第二列
A>5 ORDER BY B ——範圍查詢在第一列,排序在第二列
A IN(1,2) ORDER BY B ——理由同上
ORDER BY A ASC, B DESC ——注意,此時兩列以不同順序排序

順著組合索引怎麼建繼續往下延伸,請各位注意“索引合併”概念:
MySQL 5,0以下版本,SQL查詢時,一張表只能用一個索引(use at most only one index for each referenced table),
從 MySQL 5.0開始,引入了 index merge 概念,包括 Index Merge Union Access Algorithm(多個索引並集訪問),包括Index Merge Intersection Access Algorithm(多個索引交集訪問),可以在一個SQL查詢裡用到一張表裡的多個索引。
MySQL 在5.6.7之前,使用 index merge 有一個重要的前提條件:沒有 range 可以使用。[出自參考資源2]
索引合併的簡單說明:
MySQL 索引合併能使用多個索引
SELECT * FROM TB WHERE A=5 AND B=6
能分別使用索引(A) 和 (B) 或 索引合併;
建立組合索引(A,B) 更好;
SELECT * FROM TB WHERE A=5 OR B=6
能分別使用索引(A) 和 (B) 或 索引合併;
組合索引(A,B)不能用於此查詢,分別建立索引(A) 和 (B)會更好;
最後的總結:
仍然是強調再強調:
記住,explain 後再提測是一種美德!

相關推薦

[優化]索引注意選擇性 & 範圍查詢注意組合索引順序

文章轉自:http://www.cnblogs.com/zhengyun_ustc/p/slowquery2.html 寫在前面的話: 之前曾說過“不要求每個人一定理解 聯表查詢(join/left join/inner join等)時的mysql運算過程”,但對於欄位選擇性差意味著什麼,組合索引欄位順序意味

MySQL索引優化 & 聚簇索引 & 選擇性 & 範圍查詢 & 組合索引順序

索引B-Tree: 一般來說, MySQL 中的 B-Tree 索引的物理檔案大多都是以 B+tree的結構來儲存的,也就是所有實際需要的資料都存放於 Tree 的 Leaf Node,而且到任何一個 Leaf Node 的最短路徑的長度都是完全相同的,可能各種資料庫(或 MySQL 的各種

[優化]聯表查詢注意誰是驅動表 & 你搞不清楚誰join誰更好請放手讓mysql自行判定

夠複雜吧。Nested Loop Join 就是這樣, 以驅動表的結果集作為迴圈的基礎資料,然後將結果集中的資料作為過濾條件一條條地到下一個表中查詢資料,最後合併結果;此時還有第三個表,則將前兩個表的 Join 結果集作為迴圈基礎資料,再一次通過迴圈查詢條件到第三個表中查詢資料,如此反覆。 這條語句的

淺析MySQL中的Index Condition Pushdown (ICP 索引條件下推)和Multi-Range Read(MRR 索引範圍找)查詢優化

修正 itl iad 較高的 一句話 mysql5 條件篩選 global 查詢條件 本文出處:http://www.cnblogs.com/wy123/p/7374078.html(保留出處並非什麽原創作品權利,本人拙作還遠遠達不到,僅僅是為了鏈接到原文,因為後續對

阿里P8架構師談:MySQL資料庫的索引原理、與SQL優化的5大原則

MySQL憑藉著出色的效能、低廉的成本、豐富的資源,已經成為絕大多數網際網路公司的首選關係型資料庫。雖然效能出色,但所謂“好馬配好鞍”,如何能夠更好的使用它,已經成為開發工程師的必修課,我們經常會從職位描述上看到諸如“精通MySQL”、“SQL語句優化”、“瞭解資料庫原理”等要求。 我們知道一般

mysql索引以及SQL優化記錄【轉慕課】

原文大家可以參考下連結 mysql索引介紹以及慢SQL優化 索引介紹 【略】 SQL優化說明 執行計劃explain的使用不做說明。 1.最左字首匹配原則,非常重要的原則,mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like

MongoDB 創基礎索引組合索引、唯一索引以及優化

表示 mil cap 監控工具 actor lai slow time _id 一、索引 MongoDB 提供了多樣性的索引支持,索引信息被保存在system.indexes 中,且默認總是為_id創建索引,它的索引使用基本和MySQL 等關系型數據庫一樣。其實可以這樣說說

mysql模糊查詢unicode編碼的的解決方案——mybatis資料庫mysql對unicode支援問題

1.mysql資料庫裡的nickname欄位內容是經過unicode編碼處理後儲存的, 如:\u73\u74\u61\u72\u7a\u6d\ud83d\udc7f\u20\ud83d\ude04\u20\ud83d\ude03\u20\ud83d\ude13 實際明文:

Oracle表名小寫且加雙引號的注意事項

SQL> CREATE TABLE "test" ("ID" int, "name" NVARCHAR2(2000)); 表已建立。 SQL> drop table test; drop

有關MYSQL有關時間戳的問題

由於要做一個專案的後臺,需要設計數模並建庫,用的是PowerDesigner,資料庫用的是MySQL5.5 ,在建物理模型的時候,用到了timestamp這個型別的欄位(時間戳),一個是建立時間,一個是修改時間,建庫成功後發現一個問題,怎麼讓CREATED欄位在

es 索引指定分片資料和副本數

1指定分片數量  "number_of_shards":8 2指定副本數量   "number_of_replicas" : 1 3指定重新整理時間30s,寫入資料時,檢視到的資料與真實資料有30s的延時   "refresh_interval":"30s" 4禁用_all

(轉)mysql創反引號的作用

navi _id sta gbk ble 擴展 engine bsp div 試用navicat工具查看現網mysql建表語句時,發現表名和字段名都是反引號引起來的 CREATE TABLE `tab_notice_title_tv` ( `i_id` int(11

oracle 11g rac dbca提示創監聽

oracle 監聽 listener oracle rac Oracle 11g rac dbca建庫時提示創建監聽在安裝oracle 11g rac時,使用dbca建庫的過程中提示需要創建監聽:Default Listener "LISTENER" is not configured in

powerDesigner選擇不同數據庫類型

log des 創建表 img sql 數據 ges ima 不同數據庫 l 使用powerDesigner創建表模型的時候可選擇數據庫類型 如圖設置為mysql: powerDesigner建表時選擇不同數據庫類型

MySQL 創,設置時間字段自己主動插入當前時間

mil post div ipp strong ren current spa blog MySQL 創建表時,設置時間字段自己主動插入當前時間 DROP TABLE IF EXISTS `CONTENT`; CREATE TABLE `CONTENT`

【bzoj4276】[ONTAK2015]Bajtman i Okr?g?y Robin 線段樹優化圖+費用流

har brush while inf uil mes queue eof div 題目描述 有n個強盜,其中第i個強盜會在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]這麽多段長度為1時間中選出一個時間進行搶劫,並計劃搶走

httpClient,設置timeout時間

httpclient//private static HttpClient httpClient = HttpClientBuilder.create().build(); private static CloseableHttpClient httpClient;// = HttpClientBuilde

使用maven創springMVC返回頁面報錯

jdk1 pil maven 分享 apache art 解決 編譯 img 這是由於你的 Maven 編譯級別是 jdk1.5 或以下,而你導入了 jdk1.6 以上的依賴包 解決辦法: <build> <finalName&g

oracle 創view,授權給用戶

pla ott ger ron clas create 創建 reat grant 解決方法: 以dba用戶登錄 sqlplus / as sysdba 賦予scott用戶創建VIEW的權限 grant create view to scott

【BZOJ3681】Arietta 樹鏈剖分+可持久化線段樹優化圖+網絡流

des 持久化 -s 過程 void 但是 陽光 建圖 == 【BZOJ3681】Arietta Description Arietta 的命運與她的妹妹不同,在她的妹妹已經走進學院的時候,她仍然留在山村中。但是她從未停止過和戀人 Velding 的書信往來。一天,