电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

MySQL選錯索引的原因以及解決方案

瀏覽:3日期:2023-10-10 15:38:22

MySQL 中,可以為某張表指定多個索引,但在語句具體執行時,選用哪個索引是由 MySQL 中執行器確定的。那么執行器選擇索引的原則是什么,以及會不會出現選錯索引的情況呢?

先看這樣一個例子:

創建表 Y,設置兩個普通索引, 創建一個存儲過程用于插入數據。

MySQL: 5.7.27, 隔離級別: RR

CREATE TABLE `Y` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `a` (`a`), KEY `b` (`b`)) ENGINE=InnoDB;

delimiter ;;create procedure idata()begin declare i int; set i=1; while(i<=100000)do insert into Y (`a`,`b`) values(i, i); set i=i+1; end while;end;;delimiter ;call idata();

查看如下事務:

Session A Session B start transaction with consistent snapshot; delete from t; call idata(); explain select * from Y where a between 10000 and 20000; explain select * from Y force index(a) where a between 10000 and 20000; commit;

如果單獨執行 Session B 中 select * from Y where a between 10000 and 20000;,毫無疑問會選擇 a 這個索引。

但如果安裝 Session A,Session B 的順序執行,發現索引的選擇如下:

MySQL選錯索引的原因以及解決方案

可以發現,在 Session B 的場景下,執行器卻沒有選擇 a 所在的索引,而是選擇基于主鍵索引的全表掃描。

set long_query_time=0;--將慢查詢日志打開,并將闕值設為 0. 在記錄的日志中,可以發現 MySQL 并沒有選擇 a 所在的索引,同時花費了更長的時間。

這樣看,MySQL 的優化器不一定每次都能選擇合適的索引。想要理解出現該現象的原因,就要從優化器的選擇邏輯說起。

優化器

MySQL 中優化器的目的就是找到一個最優的執行方案,從而用最小的代價去執行語句。

優化器在選擇索引時,主要會考慮如下的因素:

掃描的行數:掃描的行數越少,就證明訪問磁盤數據的次數越少,消耗的 CPU 資源就越少。 有沒有涉及到臨時表 排序

關于掃描行數的確定

計算索引的基數

MySQL 在執行語句前,其實并不能準確的計算出掃描的行數,而是通過數學統計信息來估算記錄數。這個統計信息被稱為索引的“區分度”,在索引上不同的值越多,區分度就越高。在一個索引上不同值的個數,稱為“基數”。基數越大,索引的區分度越好。

MySQL選錯索引的原因以及解決方案

這里的 Cardinality 就是索引的基數,但基數并不是完全準確的。MySQL 是在獲取基數時,實際上是采用采樣統計的方式。

計算時,會選擇 N 個數據頁,并統計這些頁面上的不同值,得到一個平均值,然后乘以該索引的頁面數,然后得到的就是索引的基數。

在 MySQL 中,有兩種存儲索引的方式,可通過設置 innodb_stats_persistent 來切換:

on 時:表示統計信息會持久化存儲,默認 N 為 20,M 為 10. off 時,統計信息僅會存儲在內存中,默認 N 為 8,M 為 16.

由于表中數據是不斷變化的,所以當更新的值超過 1/M 時,會自動觸發索引統計。

但需要注意的是,由于是采樣統計,所以基數的值不是準確的。

預估掃描行數的錯誤

之前看到,執行 Select * from Y where a between 10000 and 20000 預估的行數是 100015,這個是能理解的,因為走的是全表掃描。

之后執行 select * from Y force index(a) where a between 10000 and 20000 預估的行數是 37116,這個就不能理解了,理想的情況下應該是 10001 行 (需要遍歷到 20001)。

而且更奇怪的是,雖然 37116 行的預估行數不太合理,但也遠小于全表掃描的 100015,為什么優化器還是選擇全表掃描呢?

首先先看第二個問題,選擇 100015 的原因是因為如果使用索引 a 的話,除了需要在 a 索引掃描外,還需要回表,主鍵索引上的查詢代價,優化器也需要算進去,所以選擇了全表掃描。

這時再看第一個問題,為什么沒有得到正確的行數。這個就和一致性視圖有關了,首先 Session A 中,開啟了一致性視圖,并沒有提交。之后的 Session 清空了 Y 表后,又重新創建了相同的數據,這時每行數據都有兩個版本,舊版本是 delete 前的數據,新版本是標記為刪除的數據。所以索引 a 上的數據其實有兩份。也就造成了行數的預估錯誤。

mysql 是通過標記刪除的方法來刪除記錄的,并不是在索引和數據文件中真正的刪除。而且由于一致性讀的保證,不能刪除 delete 的空間,再加上 insert 的空間。導致統計信息有誤。

選用錯誤索引的解決辦法

對于行數預估錯誤的情況, 可采用如下的方法:

如果遇到 EXPLAIN 和預估的行數,數值相差較大時,可以通過analyze table 來重新統計索引信息。

MySQL選錯索引的原因以及解決方案

直接通過 force index 強制指定需要使用的索引,不讓優化器進行判斷。但使用 force 也可能帶來一些問題:

遷移數據庫時,語法不支持 不容易變更并且不太方便,因為選錯索引的情況一般不會經常發生,在生產環境出現問題后,才需要改代碼,但還需要重新進行上線測試,部署。

優化 SQL 語句,引導優化器使用正確的索引

再看一個類似的例子:

MySQL選錯索引的原因以及解決方案

先來看一下這句

SQL select * from Y where a between 1 and 1000 and b between5000 100000 order by b limit 1;

在執行這句話時,可以選索引 a,也可以選索引 b. 我們知道,每個索引對應了一顆B+樹。這里由于取得是 a 和 b 的交集,如果選用索引 a 的話,需要遍歷 1 - 10001 行。選用索引 b 需要遍歷 50000 - 100001 行。理論上來說,應該選擇 a 作為索引,可以優化器又偏偏選擇了 b 作為索引。

這里選擇 b 作為索引的原因,是因為優化器看到了后面的 order by 語句,由于要排序,而 B+ 樹本身就是有序的,省去了排序的過程,所以選擇了 b 作為索引。

但從實際的執行時間來看,索引 a 執行時間更短,所以這里 MySQL 又選擇了錯誤的索引。

我們可以將上述語句中 order by b limit 改為 order by b,a limit 1 這時由于 a,b 索引都要排序,掃描的行數就成為執行器主要參考的條件,引導選擇正確的索引。

這樣做的前提一定要保證執行的邏輯結果是一致的,比如在 limit 1 的情況下,order by b,a 和 order by b 的結果一致,如果換成 limit 100 就不一定了。

MySQL選錯索引的原因以及解決方案

還有一種改發

select * from (select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 100)alias limit 1;

現在可以看到,優化器選擇了合適的索引。原因在于 limit 100 讓優化器認為,使用索引 b 的代價較高,進而選擇索引 a. 其實就是通過 limit 100 誘導優化器做出選擇。

調整索引

能否找到更優,更合適的索引,或者利用索引的原則,刪除一些不必要的索引。

總結

現在我們知道,MySQL 在選擇索引時,是會出現錯誤的情況的。優化器選擇索引的原則主要有三個,掃描的行數,是否存在臨時表,以及排序。行數的掃描,主要和基數有關,而基數的統計則是通過統計抽樣決定的,進而預估的行數可能會是不準確的。

在遇到掃描的行數不正確時,可以通過 analyze table 來重新統計表的信息,通過 force index 強制指定索引,或通過手動改變 sql 的語義,誘導優化器做出正確的選擇。

以上就是MySQL選錯索引的原因以及解決方案的詳細內容,更多關于MySQL 索引的資料請關注好吧啦網其它相關文章!

標簽: MySQL 數據庫
相關文章:
主站蜘蛛池模板: 数显恒温油浴-电砂浴-高温油浴振荡器-常州迈科诺仪器有限公司 | 制氮设备_PSA制氮机_激光切割制氮机_氮气机生产厂家-苏州西斯气体设备有限公司 | ETFE膜结构_PTFE膜结构_空间钢结构_膜结构_张拉膜_浙江萬豪空间结构集团有限公司 | 【官网】博莱特空压机,永磁变频空压机,螺杆空压机-欧能优 | 全国冰箱|空调|洗衣机|热水器|燃气灶维修服务平台-百修家电 | 不锈钢法兰-碳钢法兰-法兰盘生产加工厂家-[鼎捷峰]-不锈钢法兰-碳钢法兰-法兰盘生产加工厂家-[鼎捷峰] | 理化生实验室设备,吊装实验室设备,顶装实验室设备,实验室成套设备厂家,校园功能室设备,智慧书法教室方案 - 东莞市惠森教学设备有限公司 | 杭州可当科技有限公司—流量卡_随身WiFi_AI摄像头一站式解决方案 | 集装箱标准养护室-集装箱移动式养护室-广州璟业试验仪器有限公司 | 上海阳光泵业制造有限公司 -【官方网站】 | 硅胶布|电磁炉垫片|特氟龙胶带-江苏浩天复合材料有限公司 | 上海网站建设-上海网站制作-上海网站设计-上海做网站公司-咏熠软件 | 【同风运车官网】一站式汽车托运服务平台,验车满意再付款 | 直读光谱仪,光谱分析仪,手持式光谱仪,碳硫分析仪,创想仪器官网 | 北京中航时代-耐电压击穿试验仪厂家-电压击穿试验机 | 1000帧高速摄像机|工业高速相机厂家|科天健光电技术 | 正压送风机-多叶送风口-板式排烟口-德州志诺通风设备 | sfp光模块,高速万兆光模块工厂-性价比更高的光纤模块制造商-武汉恒泰通 | 高低温万能试验机-复合材料万能试验机-馥勒仪器 | 物联网卡_物联网卡购买平台_移动物联网卡办理_移动联通电信流量卡通信模组采购平台? | 深圳宣传片制作-企业宣传视频制作-产品视频拍摄-产品动画制作-短视频拍摄制作公司 | 反渗透阻垢剂-缓蚀阻垢剂厂家-循环水处理药剂-山东鲁东环保科技有限公司 | 刺绳_刀片刺网_刺丝滚笼_不锈钢刺绳生产厂家_安平县浩荣金属丝网制品有限公司-安平县浩荣金属丝网制品有限公司 | 建筑消防设施检测系统检测箱-电梯**检测仪器箱-北京宇成伟业科技有限责任公司 | 订做不锈钢_不锈钢定做加工厂_不锈钢非标定制-重庆侨峰金属加工厂 | 高压管道冲洗清洗机_液压剪叉式升降机平台厂家-林君机电 | 耐火砖厂家,异形耐火砖-山东瑞耐耐火材料厂| 没斑啦-专业的祛斑美白嫩肤知识网站-去斑经验分享 | 【孔氏陶粒】建筑回填陶粒-南京/合肥/武汉/郑州/重庆/成都/杭州陶粒厂家 | 泥浆在线密度计厂家-防爆数字压力表-膜盒-远传压力表厂家-江苏大亚自控设备有限公司 | 安全阀_弹簧式安全阀_美标安全阀_工业冷冻安全阀厂家-中国·阿司米阀门有限公司 | 四川实木门_成都实木门 - 蓬溪聚成门业有限公司 | 电池高低温试验箱-气态冲击箱-双层电池防爆箱|简户百科 | 共享雨伞_共享童车_共享轮椅_共享陪护床-共享产品的领先者_有伞科技 | 压缩空气冷冻式干燥机_吸附式干燥机_吸干机_沪盛冷干机 | 智慧钢琴-电钢琴-便携钢琴-数码钢琴-深圳市特伦斯乐器有限公司 | WTB5光栅尺-JIE WILL磁栅尺-B60数显表-常州中崴机电科技有限公司 | 环保袋,无纺布袋,无纺布打孔袋,保温袋,环保袋定制,环保袋厂家,环雅包装-十七年环保袋定制厂家 | 高扬程排污泵_隔膜泵_磁力泵_节能自吸离心水泵厂家-【上海博洋】 | 机械加工_绞车配件_立式离心机_减速机-洛阳三永机械厂 | 特种阀门-调节阀门-高温熔盐阀-镍合金截止阀-钛阀门-高温阀门-高性能蝶阀-蒙乃尔合金阀门-福建捷斯特阀门制造有限公司 |