日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

一次关于 Mysql 索引优化的思考

發布時間:2025/3/20 数据库 11 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一次关于 Mysql 索引优化的思考 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方?好好學java?,選擇?星標?公眾號

重磅資訊、干貨,第一時間送達今日推薦:2020年7月程序員工資統計,平均14357元,又跌了,扎心個人原創100W+訪問量博客:點擊前往,查看更多

轉自:簡書? ?作者:Fooisart

www.jianshu.com/p/efb7881f18b2

查看系統性能監控,發現有十多條慢查詢,決定將其優化。挑選其中一條典型Sql記錄其優化歷程。

1.概述

在下文的查詢優化中,主要圍繞的問題:Mysql為何會選錯索引?

2.優化歷程

2.1,定位問題

為了便于描述,貼出建表語句(表中數據約有400萬行):

MySQL > show create table demo_table\G*************************** 1\. row ***************************Table: demo_tableCreate Table: CREATE TABLE `demo_table` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵',`user_id` varchar(100) NOT NULL DEFAULT '' COMMENT '用戶ID',`source_channel` int(11) NOT NULL DEFAULT '0' COMMENT '來源',`source_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '來源ID',`category_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '分類ID',`classify_time` bigint(20) NOT NULL DEFAULT '0' COMMENT '歸類時間',`content_id` bigint(20) DEFAULT NULL COMMENT '語義模板ID',PRIMARY KEY (`id`),KEY `idx_category_id` (`category_id`),KEY `idx_classify_time` (`classify_time`),KEY `idx_channel_source_id` (`source_channel`,`source_id`)) ENGINE=InnoDB AUTO_INCREMENT=3081571 DEFAULT CHARSET=utf8mb4

業務查詢SQL-1(統計在近七天內每條content_id在表中出現的次數):

select content_id, count(1) as c from demo_table where source_channel = 2and classify_time between 1556019882000 and 1556624682000and content_id is not null group by content_id;

執行SQL-1,顯示耗時 9.35sec。顯然是不樂觀的一個值,查看其執行計劃(explain):?

id: 1select_type: SIMPLEtable: demo_tablepartitions: NULLtype: refpossible_keys: idx_classify_time,idx_channel_source_idkey: idx_channel_source_idkey_len: 4ref: constrows: 1487434filtered: 42.67Extra: Using where; Using temporary; Using filesort

從執行計劃中,可以看出,用到了索引idx_channel_source_id。而source_channel是個區分度很低的字段,當得知Mysql優化器選擇了idx_channel_source_id,個人感覺是比較吃驚的。idx_classify_time是區分度更好的索引卻沒有被選中?

強制使用idx_classify_time,驗證是否會執行效率更高,SQL-2:

select content_id, count(1) as c from demo_table force index(idx_classify_time)where source_channel = 2 and classify_time between 1556019882000and 1556624682000 and content_id is not null group by content_id;

果不其然,執行時間為:2.19 sec。那么這里開始疑惑了,Mysql優化器為何會選錯索引?繼續探究。

Mysql優化器會根據 ①掃描行數、②是否使用臨時表、③是否排序等因素進行綜合判斷。

貼出SQL-1、SQL-2的執行計劃:

SQL-1*************************** 1\. row ***************************id: 1select_type: SIMPLEtable: demo_tablepartitions: NULLtype: refpossible_keys: idx_classify_time,idx_channel_source_idkey: idx_channel_source_idkey_len: 4ref: constrows: 1487434filtered: 42.67Extra: Using where; Using temporary; Using filesortSQL-2*************************** 1\. row ***************************id: 1select_type: SIMPLEtable: demo_tablepartitions: NULLtype: rangepossible_keys: idx_classify_timekey: idx_classify_timekey_len: 8ref: NULLrows: 1410438filtered: 45.00Extra: Using where; Using temporary; Using filesort

從執行計劃的Extra參數中,可以看出 ②是否使用臨時表、③是否排序 這兩個因素完全一樣,再看掃描行數,idx_classify_time是141萬行,idx_channel_source_id是148萬行。明顯是idx_classify_time更少,為何沒有選它呢?

其實這里,優化器認為他們倆的行數是差不多的,沒有本質的差別。而在執行計劃中,有個參數確差別很大:type。

type最重要且經常遇見的六種類型:all, index, range, ref, eq_ref,const。從左到右,它們的效率依次是增強的,所以優化器根據 type類型更傾向于idx_channel_source_id。而且idx_channel_source_id的 key_len更小,這樣的話,一頁中可以掃描更多行數。

2.2,解決方案

既然Mysql優化器選錯了索引,我們如何去糾正它呢?

第一種方式:使用SQL-2中的方式,在應用程序中顯示選擇索引。由于索引可能會變更,名稱更改或者索引刪除等,這樣明顯會影響應用程序的可用性。

第二種方式:創建更合適的索引。

2.2.1 回表

在介紹如何創建更合適索引之前,先簡單介紹Mysql中的兩個基礎概念:聚簇索引,普通索引。

image-1為聚簇索引(clustered index),B+樹的節點存放的是每一行記錄;image-2為普通索引(secondary index),B+樹的節點存放的是其對應的主鍵ID。

使用索引查詢具體執行流程:

聚簇索引:如果我是根據主鍵id查詢某個值,只需要查詢主鍵索引樹即可獲取內容行R;

普通索引:第一次查詢普通索引樹,拿到字段ID,然后拿著ID值去主鍵索引樹再次查找內容行R。

從查詢流程可以看出,使用普通索引需要多掃描一次索引樹。而這個過程,稱為 回表。

2.2.2 覆蓋索引

那么如果能夠減少回表的次數,會很大程度地提升性能,這里就用到了聯合索引。將需要用到的字段,建立成一個聯合索引,那么這樣就無需再次回表。這樣也就用到了覆蓋索引,效率更高。

為了優化SQL-1,創建的索引語句如下:

alter table `demo_table`add index idx_content_id_calssify_time_source_channel(content_id,classify_time,source_channel);


再次執行SQL-1,顯示耗時?0.02sec,性能成飛躍式提升。查看SQL-1執行計劃:

id: 1select_type: SIMPLEtable: demo_tablepartitions: NULLtype: rangepossible_keys:idx_classify_time,idx_channel_source_id,idx_channel_classify_time_content_idkey: idx_channel_classify_time_content_idkey_len: 21ref: NULLrows: 1788506filtered: 50.00Extra: Using where; Using index; Using temporary; Using filesort

從執行計劃中,看Extra比之前多了個Using index,這就表示本次查詢用到了覆蓋索引,一般效率較高(基本達成三星索引的標準)。

至此,優化就結束了。

最后,再附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,筆者這幾年及春招的總結,github 1.5k star,拿去不謝! 下載方式1.?首先掃描下方二維碼2.?后臺回復「Java面試」即可獲取

總結

以上是生活随笔為你收集整理的一次关于 Mysql 索引优化的思考的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。