★SQL語句優化的一般步驟
通過show status命令瞭解SQL語句的執行頻率(重點是增刪改查)
show [session|global] status;
session:(默認)表示當前的連接
global:表示自數據庫啓動至今
也可使用like語句 show status like "Com_%";
【參數說明】
[Com_XXX] Com_select 執行select操作的次數,一次查詢只累計1,與影響行數無關
Com_update 執行update操作的次數
Com_insert 執行insert操作的次數,對於批量插入算爲1次
Com_delete 執行delete操作的次數
[InnoDB] InnoDB_rows_read 執行select操作的次數
InnoDB_rows_updated 執行update操作的次數
InnoDB_rows_insert 執行insert操作的次數
InnoDB_rows_delete 執行delete操作的次數
注:InnoDB考慮的是影響的行數
通過alter table t2 engine=innodb;可以切換成innodb表引擎
【其他參數】
connections 連接mysql的數量(無論登錄是否成功,都會被記錄下來)
uptime 服務器已經工作的秒數
slow_queries 慢查詢的次數
定位執行效率較低的SQL語句
通過慢查詢日誌來查(記錄了超過10s的語句,表明很有可能存在問題)
explain select * from table where id=100;
desc select * from t1\G
[顯示條目] id:1
select_type:SIMPLE 表示select的類型,常見取值有
SIMPLE 簡單查詢,沒有用到多表查詢或者子查詢
PRIMARY 主查詢,即外層的查詢
UNION 第二個或後面的查詢語句
SUBQUERY 子查詢中的第一個select
table:t1 輸出結果集的表
type:range 表示表的連接類型,性能由好到差依次爲
system 表僅一行、const 只一行匹配
eq_ref 對於前面的每一行使用主鍵和唯一
ref(同eq_ref,但沒有使用主鍵和唯一)
ref_or_null 同前面對null查詢
index_merge 索引合併優化、unique_subquery主鍵子查詢
index_subquery 非主鍵子查詢、range 表單中的查詢範圍
index 都通過查詢索引來得到數據、all 通過全表掃描得到數據
possible_keys:name 表查詢時可能使用到的索引
key:name 表示實際使用的索引
key_len:50 索引字段的長度
ref:NULL
rows:8 掃面行的數量 <==重點查看的內容
Extra:Using where;Using index 執行情況的說明和描述
重點看影響行數,是多表查詢還是單表查詢,有沒有用到索引,索引用到字段的最大長度
【總結】一般步驟爲:
通過慢查詢日誌查看SQL語句
通過SQL語句查看其影響行數
影響行數特別多的話要進而判斷是否需要加索引
★索引優化
索引是數據庫優化中最常見也是最重要的手段,通過索引通常可以幫助用戶解決大多數的SQL性能問題
索引用於快速找出在某個列中有一特定值的行,對相關列使用索引是提高select操作性能的最佳途徑
MyISAM存儲引擎的表的數據和索引是自動分開存儲的,各自是獨立的一個文件
InnoDB存儲引擎的表的數據和索引是存儲在同一個表空間裏面的,但可以由多個文件組成
MySQL目前不支持函數索引,但是可以針對列的前面某一部分進行索引,例如name字段,可以只取name的前4個字符進行索引,這個特性可以大大縮小索引文件的大小,因此在設計表結構的時候也可以根據此特性對文本列進行靈活設計
create index ind_com_name on com(name(4));
使用索引的情形:
對於創建的多列索引,只要查詢條件中用到最左面的列,索引一般就會被使用
create index ind_sa on sa(com,mon); 創建複合索引
explain select * from sa where com=2006\G 使用了索引
explain select * from sa where mon=100\G 沒有使用索引
使用like的查詢,後面如果是常量並且%不在第一個字符,索引纔會被使用
explain select * from com where name like "%2"\G;
百分號在後面可能會用到索引,而百分號在前面可能索引會失效
如果對大的文本進行搜索一般用全文匹配查找而不用like
如果是列名索引,搜索 col is null時會用到索引
存在索引但不使用的情形:
如果mysql估計使用索引比全表掃描更慢,則不使用索引
例如:id列均勻分佈在1-100之間,查詢時使用索引就不是很好
如果使用MEMORY/HELP表並且where條件中不使用"="進行索引列,那麼不會使用索引
用or分隔開的條件,如果or前的條件中的列有索引,而後面的列沒有索引,那麼涉及到的索引都不會被使用
使用and或者or只有前後列都有索引,涉及到的索引纔會被引用
如果列是字符串類型(name)
但查詢條件爲name=2000,這時候不會用到索引
但是name="2000" 會用到索引
查看索引的使用情況:
如果索引正在工作,Handler_read_key的值會很高,這個值代表了一個行被索引值讀的次數
Handler_read_md_next的值高則意味着查詢運行低效,並且應該建立索引補救
show status like "Handler_read%"
其他:
嵌套查詢內查詢使用索引,外查詢不使用索引
左連接兩個表都使用索引
所以要避免使用嵌套查詢,儘可能去使用連接和多表查詢
★表優化
檢測一個或多個表是否有錯誤
check table table_name;
定期優化表
optimize table sales;
如果已經刪除了表的一大部分,或者如果已經對含有可變長度行的表進行了很多次改動,則需要做定期優化。這條命令可以將表中的空間碎片進行合併,但是此命令只對MySIAM、BDB、和InnoDB表起作用
★常用的SQL優化
大量插入數據
當用load命令導入數據的時候,適當設置可以提高導入速度
[針對MyISAM引擎的表]
alter table table_name disable keys 關閉MyISAM表非唯一索引的更新
loading the data 加載數據
alter table table_name enable keys 打開MyISAM表非唯一索引的更新
注意:對InnoDB表無效
infile、onfile
select * from t1 into outfile "/tmp/test.txt"; 只保留內容,不保留表結構
load data infile "/tmp/test.txt" into table t1;
唯一性校驗
關閉唯一性校驗:set unique_checks=0
恢復唯一性校驗:set unique_checks=1
針對InnoDB表的優化
關閉自動提交可以提高導入效率 set autocommit=0 關閉自動提交
導入數據
set autocommit=1 恢復自動提交
因爲InnoDB表是按照主鍵順序來保存的,所以將導入的數據按照主鍵順序排列,可以有效的提高導入數據的效率
優化insert
儘量使用同時插入多個數據的insert語句,可以大大減少客戶與數據庫頻繁連接關閉造成的損耗
如:insert into t1 values("user1"),("user2"),("user3");
可以使用insert delayed(馬上執行)語句得到更高的效率
將索引文件和數據文件分別存放在不同的磁盤上
可以增加bull_insert_buffer_size變量值方法來提高速度(針對MyISAM表)
優化group by
如果查詢包含group by 但用戶想要避免排序結果的損耗,則可以使用order by null來禁止排序
★數據庫優化
外鍵 優化表的類型 通過拆分提高表的訪問效率
使用中間表:表或視圖(相比之下視圖更合適,視圖數據的同步更新要比錶快)
★mysql服務器優化
myisam讀鎖定、myisam寫鎖定
lock table t1 read
這時候使用另一個用戶去對t1表進行增刪改操作會發現所有的數據都只停留在終端上而沒有真正去操作
讀鎖定是自己可以讀別人也可以讀,但是誰也不能進行增刪改,解除鎖定後纔可進行相關操作
讀鎖定在對大量數據進行備份時非常有用(-L 添加讀鎖)
unlock tables; 解除鎖定
寫鎖定:只有本人可以寫,別人增刪改查都做不了
bin-log日誌
show variables like "%bin%"; 查看是否開啓了bin-log日誌
log-bin=mysql-bin (/etc/my.cnf下)
慢查詢日誌、慢查詢時間
show variables like "%slow"; 查看是否開啓了慢查詢日誌
vim /etc/my.cnf
[mysqld]
log_slow_queries=slow.log 開啓慢查詢日誌
long_query_time=5 大於2s被記載