SQL語句優化是建立在慢查詢分析的基礎上,通過慢查詢定位有問題的SQL語句,關於慢查詢的介紹及其分析工具,可以參考[mysql慢查詢及慢查詢日誌分析工具]
一、通過explain查詢
1 用法:explain sql
2 作用:用於分析sql語句
(1)、id:執行explain的一個編號(沒有實際意義)
(2)、table:查詢的表名
(3)、select_type:查詢類型,是單表查詢、聯合查詢還是子查詢等 可能會出現以下值:
例子使用的表結構:
CREATE TABLE `mall_user`(`uid`int(12) NOT NULL AUTO_INCREMENT COMMENT '用戶ID',`account` varchar(20) NOT NULL COMMENT '帳號',`email` varchar(70) NOT NULL DEFAULT '' COMMENT '郵箱',`password`char(32) NOT NULL DEFAULT '' COMMENT '密碼',`mobile`char(11) NOT NULL DEFAULT '' COMMENT '手機號',`nickname` varchar(20) NOT NULL DEFAULT '' COMMENT '暱稱',`status`enum('UNCHECKED','DISABLED','INACTIVED','ACTIVED') NOT NULL DEFAULT 'UNCHECKED' COMMENT '狀態',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入時間', PRIMARY KEY (`uid`), UNIQUE KEY `idx_account`(`account`), UNIQUE KEY `idx_email`(`email`), UNIQUE KEY `idx_mobile`(`mobile`), UNIQUE KEY `idx_nickname`(`nickname`), KEY `idx_status`(`status`), KEY `idx_ctime`(`create_time`)) ENGINE=InnoDB AUTO_INCREMENT=300004 DEFAULT CHARSET=utf8 COMMENT='用戶表';例1:simple簡單查詢:
(4). type:連接使用的類型(重要項) 顯示連接使用的類型,按最 優到最差的類型排序
例2:type為const:
例3:type為ref:
例3:type為all:(這種是要避免和優化的)
(5). prossible_keys:能在該表中使用哪些索引有助於查詢
(6). key:實際使用的索引
(7). key_len:索引的長度,在不損失精確性的情況 下,長度越短越好
(8). ref:索引的哪一列被使用了
(9). rows:返回的結果的行數
(10). Extra:其他說明
以下兩種情況說明:MYSQL 根本不能使用索引,效率會受到重大影響。應儘可能對此進行優化
二、通過show profile查看SQL執行過程
1、執行步驟
首先得開啟profiling
set profiling=1
其次是執行sql
最後通過show profile查看分析結果
可以看出上圖中的Sending data是佔用時間最長的部分,可能是原因的是查詢的數據量過大
2、查看SQL執行各階段的資源消耗情況:
用法:
show profile <type> [for QUERY <NUM>] ;
參數說明:
<type> 表示顯示的資源類型,可以使用以下的值:
<NUM>表示顯示哪條SQL(這個數字可以通過SHOW profiles的中取得,for Query 不填寫則表示最近執行的SQL)通過show profile查找出最消耗性能的階段,針對其進行優 化三、SQL語句優化
1、count語句優化
(1)count(*)與count(col)的情況下:
第一種情況:在沒有任何查詢條件的情況下:
count(*)
count(region):region是一個普通欄位,沒有任何索引
count(country):country是一個普通索引
得出的結論:在沒有where條件的情況下,速度由快到慢的是:(可以多次運行,查看結果) count(*) > count(索引欄位) > count(未索引欄位)第二種情況:在有查詢條件的情況下:
從結果可以得出以下結論:
在有where條件的情況下,速度由快到慢的是: count(where條件中包含的欄位) > count(*) > count(未索引欄位)count語句優化結論:在有where條件的情況下,儘量使用count(where條件中的查詢條件欄位),其次是使用count(),避免使用count(col);在沒有where條件的情況下,儘量使用count()2、max語句優化 在max欄位上添加索引,可以提高其查詢效率
實驗: 在沒有添加的索引的欄位使用max
添加索引後:
alter table population add index idx_population(population);
發現:添加索引後的,如果帶where條件,而且where條件與max的欄位不一致時,所花時間竟然比不帶where的多了幾個數量級的,而且比之間不加索引花的時間更多。這個得考慮一下是什麼原因。
3、子查詢優化 根據實際情況而定:
如果查詢的條件是以左表的主鍵為查詢條件的,使用IN子查詢更高效 - 如果查詢的條件不是以左表的主鍵為查詢條件的,使用聯接查詢更高效以一個用戶表和用戶與組關係表為例:用戶表結構如下:
CREATE TABLE `mall_user`(`uid`int(12) NOT NULL AUTO_INCREMENT COMMENT '用戶ID',`account` varchar(20) NOT NULL COMMENT '帳號',`email` varchar(70) NOT NULL DEFAULT '' COMMENT '郵箱',`password`char(32) NOT NULL DEFAULT '' COMMENT '密碼',`mobile`char(11) NOT NULL DEFAULT '' COMMENT '手機號',`nickname` varchar(20) NOT NULL DEFAULT '' COMMENT '暱稱',`status`enum('UNCHECKED','DISABLED','INACTIVED','ACTIVED') NOT NULL DEFAULT 'UNCHECKED' COMMENT '狀態',`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入時間', PRIMARY KEY (`uid`), UNIQUE KEY `idx_account`(`account`), UNIQUE KEY `idx_email`(`email`), UNIQUE KEY `idx_mobile`(`mobile`), UNIQUE KEY `idx_nickname`(`nickname`), KEY `idx_status`(`status`), KEY `idx_ctime`(`create_time`)) ENGINE=InnoDB AUTO_INCREMENT=300004 DEFAULT CHARSET=utf8 COMMENT='用戶表';
用戶與組關係表結構:
CREATE TABLE `mall_user_group_relation`(`group_id`int(12) NOT NULL COMMENT '組ID',`uid`int(12) NOT NULL COMMENT '用戶ID',`remark` varchar(50) NOT NULL DEFAULT '' COMMENT '備註', PRIMARY KEY (`group_id`,`uid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
原查詢語句:
select*from mall_user AS user where uid in(select distinct uid from mall_user_group_relation);
修改為關聯查詢的語句:
select distinct(user.uid),account,email,password,mobile,nickname,status,create_time from mall_user AS user RIGHT JOIN mall_user_group_relation AS relation ON user.uid=relation.uid
4、儘量避免使用select *
只獲取必要的欄位,不需要的欄位可以不用獲取。select * 查詢一些不必要的數據,會造成系統資源的極大浪費,特別是查詢數據量較多的數據時。
5、總結:
在where條件、order by、group by中儘量使用已經索引的欄位查詢必要的欄位和限定的記錄數(limit)不要完全相信已有經驗,需要自己根據explain和show profile來檢測SQL的執行效率,進行針對性的優化