亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > MySQL > 正文

sql語句優化的一般步驟詳解

2024-07-24 13:14:22
字體:
來源:轉載
供稿:網友

前言

本文主要給大家分享了關于sql語句優化的一般步驟,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

一、通過 show status 命令了解各種 sql 的執行頻率

mysql 客戶端連接成功后,通過 show [session|global] status 命令可以提供服務器狀態信息,也可以在操作系統上使用 mysqladmin extend-status 命令獲取這些消息。

show status 命令中間可以加入選項 session(默認) 或 global:

  • session (當前連接)
  • global (自數據上次啟動至今)
# Com_xxx 表示每個 xxx 語句執行的次數。mysql> show status like 'Com_%';

我們通常比較關心的是以下幾個統計參數:

  • Com_select : 執行 select 操作的次數,一次查詢只累加 1。
  • Com_insert : 執行 insert 操作的次數,對于批量插入的 insert 操作,只累加一次。
  • Com_update : 執行 update 操作的次數。
  • Com_delete : 執行 delete 操作的次數。

上面這些參數對于所有存儲引擎的表操作都會進行累計。下面這幾個參數只是針對 innodb 的,累加的算法也略有不同:

  • Innodb_rows_read : select 查詢返回的行數。
  • Innodb_rows_inserted : 執行 insert 操作插入的行數。
  • Innodb_rows_updated : 執行 update 操作更新的行數。
  • Innodb_rows_deleted : 執行 delete 操作刪除的行數。

通過以上幾個參數,可以很容易地了解當前數據庫的應用是以插入更新為主還是以查詢操作為主,以及各種類型的 sql 大致的執行比例是多少。對于更新操作的計數,是對執行次數的計數,不論提交還是回滾都會進行累加。

對于事務型的應用,通過 Com_commitCom_rollback 可以了解事務提交和回滾的情況,對于回滾操作非常頻繁的數據庫,可能意味著應用編寫存在問題。

此外,以下幾個參數便于用戶了解數據庫的基本情況:

  • Connections : 試圖連接 mysql 服務器的次數。
  • Uptime : 服務器工作時間。
  • Slow_queries : 慢查詢次數。

二、定義執行效率較低的 sql 語句

1. 通過慢查詢日志定位那些執行效率較低的 sql 語句,用 --log-slow-queries[=file_name] 選項啟動時,mysqld 寫一個包含所有執行時間超過 long_query_time 秒的 sql 語句的日志文件。

2. 慢查詢日志在查詢結束以后才記錄,所以在應用反映執行效率出現問題的時候慢查詢日志并不能定位問題,可以使用 show processlist 命令查看當前 mysql 在進行的線程,包括線程的狀態、是否鎖表等,可以實時的查看 sql 的執行情況,同時對一些鎖表操作進行優化。

三、通過 explain 分析低效 sql 的執行計劃

測試數據庫地址:https://downloads.mysql.com/docs/sakila-db.zip(本地下載)

統計某個 email 為租賃電影拷貝所支付的總金額,需要關聯客戶表 customer 和 付款表 payment , 并且對付款金額 amount 字段做求和(sum) 操作,相應的執行計劃如下:

mysql> explain select sum(amount) from customer a , payment b where a.customer_id= b.customer_id and a.email='JANE.BENNETT@sakilacustomer.org'/G *************************** 1. row ***************************  id: 1 select_type: SIMPLE table: a partitions: NULL  type: ALLpossible_keys: PRIMARY  key: NULL key_len: NULL  ref: NULL  rows: 599 filtered: 10.00 Extra: Using where*************************** 2. row ***************************  id: 1 select_type: SIMPLE table: b partitions: NULL  type: refpossible_keys: idx_fk_customer_id  key: idx_fk_customer_id key_len: 2  ref: sakila.a.customer_id  rows: 26 filtered: 100.00 Extra: NULL2 rows in set, 1 warning (0.00 sec)
  • select_type: 表示 select 類型,常見的取值有:
         simple:簡單表,及不使用表連接或者子查詢
         primary:主查詢,即外層的查詢
         union:union 中的第二個或后面的查詢語句
         subquery: 子查詢中的第一個 select
  • table : 輸出結果集的表
  • type : 表示 mysql 在表中找到所需行的方式,或者叫訪問類型,常見類型性能由差到最好依次是:all、index、range、ref、eq_ref、const,system、null:

1.type=ALL,全表掃描,mysql 遍歷全表來找到匹配的行:

mysql> explain select * from film where rating > 9 /G*************************** 1. row ***************************  id: 1 select_type: SIMPLE table: film partitions: NULL type: ALLpossible_keys: NULL  key: NULL key_len: NULL  ref: NULL rows: 1000 filtered: 33.33 Extra: Using where1 row in set, 1 warning (0.01 sec)

2.type=index, 索引全掃描,mysql 遍歷整個索引來查詢匹配的行

mysql> explain select title form film/G*************************** 1. row ***************************  id: 1 select_type: SIMPLE table: film partitions: NULL type: indexpossible_keys: NULL  key: idx_title key_len: 767  ref: NULL rows: 1000 filtered: 100.00 Extra: Using index1 row in set, 1 warning (0.00 sec)

3.type=range,索引范圍掃描,常見于<、<=、>、>=、between等操作:

mysql> explain select * from payment where customer_id >= 300 and customer_id <= 350 /G *************************** 1. row ***************************  id: 1 select_type: SIMPLE table: payment partitions: NULL type: rangepossible_keys: idx_fk_customer_id  key: idx_fk_customer_id key_len: 2  ref: NULL rows: 1350 filtered: 100.00 Extra: Using index condition1 row in set, 1 warning (0.07 sec)

4.type=ref, 使用非唯一索引掃描或唯一索引的前綴掃描,返回匹配某個單獨值的記錄行,例如:

mysql> explain select * from payment where customer_id = 350 /G *************************** 1. row ***************************  id: 1 select_type: SIMPLE table: payment partitions: NULL type: refpossible_keys: idx_fk_customer_id  key: idx_fk_customer_id key_len: 2  ref: const rows: 23 filtered: 100.00 Extra: NULL1 row in set, 1 warning (0.01 sec)

索引 idx_fk_customer_id 是非唯一索引,查詢條件為等值查詢條件 customer_id = 350, 所以掃描索引的類型為 ref。ref 還經常出現在 join 操作中:

mysql> explain select b.*, a.* from payment a,customer b where a.customer_id = b.customer_id /G*************************** 1. row ***************************  id: 1 select_type: SIMPLE table: b partitions: NULL type: ALLpossible_keys: PRIMARY  key: NULL key_len: NULL  ref: NULL rows: 599 filtered: 100.00 Extra: NULL*************************** 2. row ***************************  id: 1 select_type: SIMPLE table: a partitions: NULL type: refpossible_keys: idx_fk_customer_id  key: idx_fk_customer_id key_len: 2  ref: sakila.b.customer_id rows: 26 filtered: 100.00 Extra: NULL2 rows in set, 1 warning (0.00 sec)

5.type=eq_ref,類似 ref,區別就在使用的索引時唯一索引,對于每個索引的鍵值,表中只要一條記錄匹配;簡單的說,就是多表連接中使用 primary key 或者 unique index 作為關聯條件。

mysql> explain select * from film a , film_text b where a.film_id = b.film_id /G*************************** 1. row ***************************  id: 1 select_type: SIMPLE table: b partitions: NULL type: ALLpossible_keys: PRIMARY  key: NULL key_len: NULL  ref: NULL rows: 1000 filtered: 100.00 Extra: NULL*************************** 2. row ***************************  id: 1 select_type: SIMPLE table: a partitions: NULL type: eq_refpossible_keys: PRIMARY  key: PRIMARY key_len: 2  ref: sakila.b.film_id rows: 1 filtered: 100.00 Extra: Using where2 rows in set, 1 warning (0.03 sec)

6.type=const/system,單表中最多有一個匹配行,查起來非常迅速,所以這個匹配行中的其他列的值可以被優化器在當前查詢中當作常量來處理,例如,根據主鍵 primary key 或者唯一索引 unique index 進行查詢。

mysql> create table test_const ( ->  test_id int, ->  test_context varchar(10), ->  primary key (`test_id`), -> ); insert into test_const values(1,'hello');explain select * from ( select * from test_const where test_id=1 ) a /G*************************** 1. row ***************************  id: 1 select_type: SIMPLE table: test_const partitions: NULL type: constpossible_keys: PRIMARY  key: PRIMARY key_len: 4  ref: const rows: 1 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec)

7.type=null, mysql 不用訪問表或者索引,直接就能夠得到結果:

mysql> explain select 1 from dual where 1 /G*************************** 1. row ***************************  id: 1 select_type: SIMPLE table: NULL partitions: NULL type: NULLpossible_keys: NULL  key: NULL key_len: NULL  ref: NULL rows: NULL filtered: NULL Extra: No tables used1 row in set, 1 warning (0.00 sec)

  類型 type 還有其他值,如 ref_or_null (與 ref 類似,區別在于條件中包含對 null 的查詢)、index_merge(索引合并優化)、unique_subquery (in 的后面是一個查詢主鍵字段的子查詢)、index_subquery(與 unique_subquery 類似,區別在于 in 的后面是查詢非唯一索引字段的子查詢)等。

  • possible_keys : 表示查詢時可能使用的索引。
  • key :表示實際使用索引
  • key-len : 使用到索引字段的長度。
  • rows : 掃描行的數量
  • extra:執行情況的說明和描述,包含不適合在其他列中顯示但是對執行計劃非常重要的額外信息。

show warnings 命令

執行explain 后再執行 show warnings,可以看到sql 真正被執行之前優化器做了哪些 sql 改寫:

MySQL [sakila]> explain select sum(amount) from customer a , payment b where 1=1 and a.customer_id = b.customer_id and email = 'JANE.BENNETT@sakilacustomer.org'/G*************************** 1. row ***************************  id: 1 select_type: SIMPLE table: a partitions: NULL  type: ALLpossible_keys: PRIMARY  key: NULL key_len: NULL  ref: NULL  rows: 599 filtered: 10.00 Extra: Using where*************************** 2. row ***************************  id: 1 select_type: SIMPLE table: b partitions: NULL  type: refpossible_keys: idx_fk_customer_id  key: idx_fk_customer_id key_len: 2  ref: sakila.a.customer_id  rows: 26 filtered: 100.00 Extra: NULL2 rows in set, 1 warning (0.00 sec)MySQL [sakila]> show warnings;+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Level | Code | Message                               |+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Note | 1003 | /* select#1 */ select sum(`sakila`.`b`.`amount`) AS `sum(amount)` from `sakila`.`customer` `a` join `sakila`.`payment` `b` where ((`sakila`.`b`.`customer_id` = `sakila`.`a`.`customer_id`) and (`sakila`.`a`.`email` = 'JANE.BENNETT@sakilacustomer.org')) |+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+1 row in set (0.00 sec)

從 warning 的 message 字段中能夠看到優化器自動去除了 1=1 恒成立的條件,也就是說優化器在改寫 sql 時會自動去掉恒成立的條件。

explain 命令也有對分區的支持.

MySQL [sakila]> CREATE TABLE `customer_part` ( -> `customer_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, -> `store_id` tinyint(3) unsigned NOT NULL, -> `first_name` varchar(45) NOT NULL, -> `last_name` varchar(45) NOT NULL, -> `email` varchar(50) DEFAULT NULL, -> `address_id` smallint(5) unsigned NOT NULL, -> `active` tinyint(1) NOT NULL DEFAULT '1', -> `create_date` datetime NOT NULL, -> `last_update` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -> PRIMARY KEY (`customer_id`) ->  -> ) partition by hash (customer_id) partitions 8;Query OK, 0 rows affected (0.06 sec)MySQL [sakila]> insert into customer_part select * from customer;Query OK, 599 rows affected (0.06 sec)Records: 599 Duplicates: 0 Warnings: 0MySQL [sakila]> explain select * from customer_part where customer_id=130/G*************************** 1. row ***************************  id: 1 select_type: SIMPLE table: customer_part partitions: p2  type: constpossible_keys: PRIMARY  key: PRIMARY key_len: 2  ref: const  rows: 1 filtered: 100.00 Extra: NULL1 row in set, 1 warnings (0.00 sec)

可以看到 sql 訪問的分區是 p2。

四、通過 performance_schema 分析 sql 性能

舊版本的 mysql 可以使用 profiles 分析 sql 性能,我用的是5.7.18的版本,已經不允許使用 profiles 了,推薦用
performance_schema 分析sql。

五、通過 trace 分析優化器如何選擇執行計劃。

mysql5.6 提供了對 sql 的跟蹤 trace,可以進一步了解為什么優化器選擇 A 執行計劃而不是 B 執行計劃,幫助我們更好的理解優化器的行為。

使用方式:首先打開 trace ,設置格式為 json,設置 trace 最大能夠使用的內存大小,避免解析過程中因為默認內存過小而不能夠完整顯示。

MySQL [sakila]> set optimizer_trace="enabled=on",end_markers_in_json=on;Query OK, 0 rows affected (0.00 sec)MySQL [sakila]> set optimizer_trace_max_mem_size=1000000;Query OK, 0 rows affected (0.00 sec)

接下來執行想做 trace 的 sql 語句,例如像了解租賃表 rental 中庫存編號 inventory_id 為 4466 的電影拷貝在出租日期 rental_date 為 2005-05-25 4:00:00 ~ 5:00:00 之間出租的記錄:

mysql> select rental_id from rental where 1=1 and rental_date >= '2005-05-25 04:00:00' and rental_date <= '2005-05-25 05:00:00' and inventory_id=4466;+-----------+| rental_id |+-----------+| 39 |+-----------+1 row in set (0.06 sec)MySQL [sakila]> select * from information_schema.optimizer_trace/G*************************** 1. row ***************************    QUERY: select * from infomation_schema.optimizer_trace    TRACE: { "steps": [ ] /* steps */}MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0  INSUFFICIENT_PRIVILEGES: 01 row in set (0.00 sec)

六、 確定問題并采取相應的優化措施

經過以上步驟,基本就可以確認問題出現的原因。此時可以根據情況采取相應的措施,進行優化以提高執行的效率。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。


注:相關教程知識閱讀請移步到MYSQL教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲欧美制服综合另类| 国产精品高潮呻吟久久av无限| 亚洲精品97久久| 社区色欧美激情 | 91高清免费视频| 欧美自拍大量在线观看| 久久天天躁夜夜躁狠狠躁2022| 亚洲qvod图片区电影| 日韩av网址在线| 精品调教chinesegay| 国产精品www| 久久精彩免费视频| 日本国产精品视频| 日韩av大片在线| 国产欧洲精品视频| 欧美最猛黑人xxxx黑人猛叫黄| 日韩欧美成人免费视频| 91免费精品国偷自产在线| 庆余年2免费日韩剧观看大牛| 国内精品视频久久| 77777少妇光屁股久久一区| 九九精品视频在线观看| 美女扒开尿口让男人操亚洲视频网站| 亚洲精品在线视频| 91精品国产高清| 亚洲一区二区三区视频播放| 欧美视频二区36p| 大量国产精品视频| 欧美性20hd另类| 欧美日韩中文字幕在线视频| 日韩av中文字幕在线免费观看| 国产精品一区二区三| 2019中文字幕免费视频| 国产精品自拍偷拍视频| 色噜噜亚洲精品中文字幕| 色琪琪综合男人的天堂aⅴ视频| 久久综合网hezyo| 国模gogo一区二区大胆私拍| 欧美性猛交xxxx免费看漫画| 国产精品九九九| 久久97精品久久久久久久不卡| 亚洲精品日韩av| 一区二区成人av| 日韩电视剧在线观看免费网站| 亚洲精品一区中文| 亚洲精品在线91| 日韩中文综合网| 日韩亚洲在线观看| 精品亚洲aⅴ在线观看| 国产z一区二区三区| 中文字幕成人在线| 国产精品高潮呻吟久久av黑人| 欧美乱妇40p| 亚洲免费影视第一页| 久久噜噜噜精品国产亚洲综合| 日韩电影中文字幕| 一区二区三区无码高清视频| 自拍偷拍亚洲欧美| www.xxxx欧美| 日韩专区中文字幕| 亚洲香蕉av在线一区二区三区| 亚洲毛片一区二区| 日韩精品免费综合视频在线播放| 97国产精品视频人人做人人爱| 成人精品久久一区二区三区| 国产精品色视频| 欧美大片va欧美在线播放| 96国产粉嫩美女| 夜夜嗨av色一区二区不卡| 欧美日韩第一页| 亚洲在线视频福利| 91美女片黄在线观| 亚洲免费视频在线观看| 欧美在线免费观看| 亚洲精品白浆高清久久久久久| 亚洲女人天堂视频| 在线午夜精品自拍| 中文字幕在线视频日韩| 亚洲精品v天堂中文字幕| 欧美性猛交xxxx乱大交| 亚洲自拍av在线| 91精品国产九九九久久久亚洲| 日韩免费精品视频| 欧美视频裸体精品| 欧美电影免费观看电视剧大全| 国产91色在线播放| 91九色蝌蚪国产| 性色av香蕉一区二区| 岛国av一区二区在线在线观看| 国产成人在线一区二区| 欧美怡春院一区二区三区| 在线视频一区二区| 97视频com| 少妇高潮 亚洲精品| 亚洲精品美女网站| 日韩精品中文字幕在线播放| 亚洲国产一区自拍| 国产高清视频一区三区| 国产精品电影网站| 欧美美女15p| 亚洲人成在线一二| 亚洲激情在线视频| 中文字幕日韩欧美在线视频| 久久久久久久影视| www欧美日韩| 亚洲福利视频专区| 亚洲黄色www网站| 日本91av在线播放| 日韩在线视频免费观看| 宅男66日本亚洲欧美视频| 少妇高潮久久久久久潘金莲| 日韩暖暖在线视频| 日韩电影中文 亚洲精品乱码| 96sao精品视频在线观看| 一区二区国产精品视频| 中文字幕最新精品| 国产一区二区激情| 日韩av一区二区在线| 国内精品久久久久久影视8| 欧美日韩亚洲国产一区| 在线视频精品一| 日韩欧美精品免费在线| 日韩电影免费观看在线| 国产一区二区三区视频免费| 国产性猛交xxxx免费看久久| 精品中文字幕在线观看| 欧美性xxxx在线播放| 国产精品爽黄69| 国内伊人久久久久久网站视频| 亚洲成成品网站| 亚洲欧美成人一区二区在线电影| 国产精品视频永久免费播放| 国产日韩欧美电影在线观看| 亚洲视频网站在线观看| 久久人人爽人人爽人人片亚洲| 日韩av一区在线| 日韩欧美综合在线视频| 91精品国产自产在线老师啪| 有码中文亚洲精品| 亚洲va男人天堂| 久久久久免费视频| 国产精品黄页免费高清在线观看| 亚洲自拍中文字幕| 欧美激情乱人伦| 中文字幕亚洲精品| 精品久久久久久久大神国产| 红桃av永久久久| 国产精品久久久久久中文字| 国产精品永久免费观看| 91国产美女在线观看| 精品人伦一区二区三区蜜桃免费| 91精品久久久久久久久久| 欧美精品久久一区二区| 亚洲美女精品久久| 欧美噜噜久久久xxx| 亚洲美女中文字幕| 亚洲精品福利在线| 国内精品在线一区| 国产亚洲aⅴaaaaaa毛片| 九九热精品视频国产| 欧美日韩在线另类| 欧美日本精品在线| 久久99热精品这里久久精品| 久久成人精品一区二区三区|