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

歡迎訪問 生活随笔!

生活随笔

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

数据库

从原理上理解MySQL的优化建议

發(fā)布時間:2024/1/23 数据库 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从原理上理解MySQL的优化建议 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

概述

自從學習 MySQL 以來,我們一直聽到或者看到很多優(yōu)化建議,比如說不要用 select * 查詢,用什么字段就查什么字段;建議用自增主鍵來作為表的主鍵,等等。這些建議聽得很多感覺都成了 MySQL 開發(fā)的常識了,但是對于這些優(yōu)化建議,我們有沒有想過為什么要這么做呢?這篇博文我們從 MySQL 的原理出發(fā),來解釋下為什么有這些優(yōu)化建議?

本文實驗環(huán)境 MySQL 5.7.25

預備知識

B+ 樹索引

MySQL 的默認存儲引擎 InnoDB 使用 B+ 樹來存儲數(shù)據(jù)的,所以在分析優(yōu)化建議之前,我們有必要了解 B+ 樹索引的基本原理。

上圖是一個 B + 樹索引示意圖(B+ 樹的定義可以看這里),每個節(jié)點表示一個磁盤塊,也可以理解為數(shù)據(jù)庫中的頁。我們來分析下 B+ 樹索引的查找過程,如果我要查詢主鍵為 35 的數(shù)據(jù),索引會怎么走呢?首先會判斷 35 小于根節(jié)點 37 ,繼續(xù)查詢左子樹,判斷 35 大于 22 和 33 那么進入其右子樹,找到了葉子節(jié)點 33 ,繼續(xù)遍歷找到了 35 ,最后取出其 data 即可。在索引的情況下,查詢 35 只用了3次 IO 操作,這是非常高效的。在真實的場景下,3層的b+樹可以表示上百萬的數(shù)據(jù),如果上百萬的數(shù)據(jù)查找只需要三次IO,性能提高將是巨大的,如果沒有索引,每個數(shù)據(jù)項都要發(fā)生一次IO,那么總共需要百萬次的IO,顯然成本非常非常高。上圖中也是體現(xiàn)了只要維持樹的高度足夠低,IO 操作就會足夠少,IO次數(shù)少,查詢性能就會高。

Explain 執(zhí)行計劃

上圖就是一個 explian 執(zhí)行計劃,先看看上面各個字段的含義是什么?

  • id:?Query Optimizer 所選定的執(zhí)行計劃中的查詢編號。
  • select_type:?所使用的查詢類型,主要有幾種查詢類型:

  • table:?顯示執(zhí)行這一步所訪問的數(shù)據(jù)庫中的表的名稱。
  • partitions:?查詢分區(qū)表匹配的分區(qū),非分區(qū)表顯示 NULL 。
  • type:?查詢表所使用的方式,類型如下:

  • 他們的性能由好到差依次是:system > const > eq_ref > ref > full_text > ref_or_null > unique_subquery > index_subquery > range > index_merge > index > all?。
  • possible_keys:?查詢可能用到的索引。
  • key_len:?用到的索引長度。
  • ref:?展示將那些列或者常量與命中的索引比較。
  • rows:?執(zhí)行這次查詢掃描的行數(shù)。
  • filtered:?過濾行數(shù)百分比,最大值是100,當顯示100時候,表示沒有過濾行, rows顯示了檢查的估計行數(shù),乘以過濾百分比將顯示與下表連接的行數(shù)。例如,如果行數(shù)為1000,過濾條件為50.00(50%),則與下表聯(lián)接的行數(shù)為1000×50%= 500。
  • extra:?執(zhí)行查詢額外的條件。

掌握了前面這些前置知識,我們來用這些知識分析下經(jīng)常建議我們的那些MySQL優(yōu)化建議。

為什么建議使用自增主鍵

當我們每次建立表的時候都在考慮是用自增主鍵呢?還是用 UUID 呢?但是從性能考慮我們還是建議使用自增 Id,為什么呢?主要是由于 MySQL B+ 樹索引性質(zhì)決定的,數(shù)據(jù)的新增是要更新索引的,也就是要更新 B+ 樹。換句話說,使用自增Id 和 非自增 Id 哪種更新 B+ 樹更快,成本更低,誰就是更優(yōu)的選擇。我們來模擬下自增 Id 插入和非自增 Id 插入情況。

自增Id 插入情況:?我們在一個已經(jīng)有10條數(shù)據(jù)的 B + 數(shù)上插入2條數(shù)據(jù),分別是10和11,我們看看樹是如何變化的。

我們這里可以發(fā)現(xiàn)兩個特點:

1、自增的數(shù)據(jù)插入影響的范圍永遠只有最右的子樹,要么直接在子樹插入節(jié)點,要么就是子樹分裂,影響其父節(jié)點。

2、除了最右子樹,其他子樹的節(jié)點都是滿的。

上面兩個特點有什么影響呢?我們根據(jù)前面 B+ 樹索引示意圖可以知道,每個點都是一個磁盤塊,操作每個節(jié)點相當于進行一次 IO,由于每次插入影響的節(jié)點只有最右子樹,那么磁盤 IO 的范圍就可控;最重要一點是除最右子樹,其他子樹的節(jié)點都是滿的,這種情況,葉子節(jié)點數(shù)據(jù)的物理連續(xù)性會更好,?根據(jù)局部性原理,查詢性能也會更高。

非自增 Id 插入情況:

非自增 Id 插入特點對比自增 Id 插入我們很容易就能知道:

1、插入影響節(jié)點不可控,無法預知。

2、每個子樹都存在葉子節(jié)點不滿的情況。

按照之前的分析思路,我們也就知道了非自增 Id 插入有什么性能劣勢了。由于插入數(shù)據(jù)影響節(jié)點不可控,導致節(jié)點分裂的情況就會更頻繁,節(jié)點分裂也是 IO 操作,性能自然受到影響。子樹的葉子節(jié)點不滿,會導致葉子節(jié)點物理連續(xù)性不好。最后如果我們是UUID的話,Id 過長,會占用節(jié)點空間,每個頁能存儲的節(jié)點變少,頁分裂變多,性能也會受到影響。這也是為什么建議使用自增主鍵的原因。

為什么不要使用 select * 查詢

我們經(jīng)常聽到查詢表,只要查詢自己想要的字段,不需要的字段就不要查詢,嚴禁使用?select *,我們能想到很直觀的理由就是,數(shù)據(jù)庫要幫你翻譯成每個字段名去查詢,接著查詢多余的字段會占用內(nèi)存,帶寬等資源。這確實是一個理由,而且這個理由很重要,但是我這里想說的是另外一個原因,覆蓋索引。我之前的一篇索引文章也介紹了覆蓋索引,感興趣的同學可以點擊這里。覆蓋索引的意思是指查詢使用聯(lián)合索引覆蓋了要查詢的字段,這樣數(shù)據(jù)庫不用去進行回表,從而減少IO,提高性能。

這里我用MySQL官方給的示列數(shù)據(jù)進行一個實驗,數(shù)據(jù)地址下載可以點擊這里。

我選擇?employees?表數(shù)據(jù)進行演示,默認數(shù)據(jù)是沒有聯(lián)合索引的,我們加上一個聯(lián)合索引:

---employee表結(jié)構(gòu)----------- +------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+---------------+------+-----+---------+-------+ | emp_no | int(11) | NO | PRI | NULL | | | birth_date | date | NO | | NULL | | | first_name | varchar(14) | NO | MUL | NULL | | | last_name | varchar(16) | NO | | NULL | | | gender | enum('M','F') | NO | | NULL | | | hire_date | date | NO | | NULL | | +------------+---------------+------+-----+---------+-------+ALTER TABLE employees.employees add Index `idx_first_name_last_name` (first_name,last_name);

查看該表索引情況:show index from employees.employees;

表已經(jīng)成功創(chuàng)建了first_name?和?last_name的符合索引,我們開啟 profiles 監(jiān)控 SQL 執(zhí)行的情況。

SET SESSION profiling = 1;

然后分別執(zhí)行以下SQL

SELECT first_name,last_name FROM employees.employees WHERE first_name='Eric'; SELECT * FROM employees.employees WHERE first_name='Eric';

查看Profiles;

這里我們看到使用 select * 比 select 字段慢了4倍左右,為什么會這樣呢?我們看看執(zhí)行計劃。

我們看到兩者的執(zhí)行計劃幾乎一樣,只有 Extra 有區(qū)別,使用字段的 Extra 顯示 using index,這就告訴你只使用索引就找到了想要的數(shù)據(jù),因為你的索引就是用?first_name?和?last_name?建立的, 而 select * 它還需要查詢?gender和hire_date字段(主鍵字段不用額外查,輔助索引指向的就是主鍵),所以它不能不進行回表查詢其他字段,性能差異也是這里。

總結(jié)

本文從原理上分析了我們?nèi)粘5膬牲c建議,為什么建議使用自增主鍵?為什么不建議使用 select * 查詢?其實主要最終的原因還是和索引相關(guān),既然我們用索引來提高我們的效率就要充分利用它,下面是知識點總結(jié):

1、B+ 樹查詢的效率高低是受其樹高影響,樹的高度越低,查詢IO次數(shù)越少,性能相對也就越高。

2、執(zhí)行計劃的類型由好到差依次是:system > const > eq_ref > ref > full_text > ref_or_null > unique_subquery > index_subquery > range > index_merge > index > all?。

3、自增主鍵的好處就是連續(xù),插入維護的成本相對較低,同時子樹的葉子節(jié)點大部分是滿節(jié)點,物理連續(xù)性好,查詢性能更優(yōu)。

4、UUID 主鍵長度過長,導致單個子節(jié)點存儲的主鍵變少,更平凡的出發(fā)頁分裂,影響性能,這也是為什么建議索引不要太長的原因。

5、覆蓋索引是很好的優(yōu)化技巧,可以讓查詢直接通過索引返回數(shù)據(jù),而不用回表,減少IO,提升性能。

參考

1、https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

2、https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-join-types

3、http://blog.codinglabs.org/articles/theory-of-mysql-index.html

來源:開源中國

作者:木木匠

原文:https://my.oschina.net/luozhou/blog/4289527

總結(jié)

以上是生活随笔為你收集整理的从原理上理解MySQL的优化建议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。