查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
總影響行數-2*實際update數, 即新增的行數.
3: 簡化union
比如有新聞表,news , news_hot,
new_hot是一張內存表,非常快,用來今天的熱門新聞.
首頁取新聞時,邏輯是這樣的:
先取hot, 沒有再取news,為了省事,用一個union來完成.
select nid,title from news_hot where nid=xxx
union
select nid,title from news where nid=xxx;
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
總影響行數-2*實際update數, 即新增的行數.
3: 簡化union
比如有新聞表,news , news_hot,
new_hot是一張內存表,非常快,用來今天的熱門新聞.
首頁取新聞時,邏輯是這樣的:
先取hot, 沒有再取news,為了省事,用一個union來完成.
select nid,title from news_hot where nid=xxx
union
select nid,title from news where nid=xxx;
如何利用變量讓後半句select不執行,
select id,content,(@find := 1) from news where id=1
union
select id,content,(@find :=1) from news2 where id=1 and (@find <= 0)
union 1,1,1 where (@find :=null) is not null;
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
總影響行數-2*實際update數, 即新增的行數.
3: 簡化union
比如有新聞表,news , news_hot,
new_hot是一張內存表,非常快,用來今天的熱門新聞.
首頁取新聞時,邏輯是這樣的:
先取hot, 沒有再取news,為了省事,用一個union來完成.
select nid,title from news_hot where nid=xxx
union
select nid,title from news where nid=xxx;
如何利用變量讓後半句select不執行,
select id,content,(@find := 1) from news where id=1
union
select id,content,(@find :=1) from news2 where id=1 and (@find <= 0)
union 1,1,1 where (@find :=null) is not null;
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
Eg;
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
總影響行數-2*實際update數, 即新增的行數.
3: 簡化union
比如有新聞表,news , news_hot,
new_hot是一張內存表,非常快,用來今天的熱門新聞.
首頁取新聞時,邏輯是這樣的:
先取hot, 沒有再取news,為了省事,用一個union來完成.
select nid,title from news_hot where nid=xxx
union
select nid,title from news where nid=xxx;
如何利用變量讓後半句select不執行,
select id,content,(@find := 1) from news where id=1
union
select id,content,(@find :=1) from news2 where id=1 and (@find <= 0)
union 1,1,1 where (@find :=null) is not null;
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
Eg;
在這個例子中, 1,2兩行,先排好序, 在內存中,就是這樣的順序[2] [1]
再逐行where條件判斷,取值.
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
總影響行數-2*實際update數, 即新增的行數.
3: 簡化union
比如有新聞表,news , news_hot,
new_hot是一張內存表,非常快,用來今天的熱門新聞.
首頁取新聞時,邏輯是這樣的:
先取hot, 沒有再取news,為了省事,用一個union來完成.
select nid,title from news_hot where nid=xxx
union
select nid,title from news where nid=xxx;
如何利用變量讓後半句select不執行,
select id,content,(@find := 1) from news where id=1
union
select id,content,(@find :=1) from news2 where id=1 and (@find <= 0)
union 1,1,1 where (@find :=null) is not null;
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
Eg;
在這個例子中, 1,2兩行,先排好序, 在內存中,就是這樣的順序[2] [1]
再逐行where條件判斷,取值.
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
總影響行數-2*實際update數, 即新增的行數.
3: 簡化union
比如有新聞表,news , news_hot,
new_hot是一張內存表,非常快,用來今天的熱門新聞.
首頁取新聞時,邏輯是這樣的:
先取hot, 沒有再取news,為了省事,用一個union來完成.
select nid,title from news_hot where nid=xxx
union
select nid,title from news where nid=xxx;
如何利用變量讓後半句select不執行,
select id,content,(@find := 1) from news where id=1
union
select id,content,(@find :=1) from news2 where id=1 and (@find <= 0)
union 1,1,1 where (@find :=null) is not null;
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
Eg;
在這個例子中, 1,2兩行,先排好序, 在內存中,就是這樣的順序[2] [1]
再逐行where條件判斷,取值.
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
總影響行數-2*實際update數, 即新增的行數.
3: 簡化union
比如有新聞表,news , news_hot,
new_hot是一張內存表,非常快,用來今天的熱門新聞.
首頁取新聞時,邏輯是這樣的:
先取hot, 沒有再取news,為了省事,用一個union來完成.
select nid,title from news_hot where nid=xxx
union
select nid,title from news where nid=xxx;
如何利用變量讓後半句select不執行,
select id,content,(@find := 1) from news where id=1
union
select id,content,(@find :=1) from news2 where id=1 and (@find <= 0)
union 1,1,1 where (@find :=null) is not null;
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
Eg;
在這個例子中, 1,2兩行,先排好序, 在內存中,就是這樣的順序[2] [1]
再逐行where條件判斷,取值.
對比這2張圖,分析:
1: where先發揮作用,把需要的行都給找出
2: 然後再逐行select
因此, 前者, 最終select時,select@num變量,都是一個值
後者,不斷select,不斷修改@num的值, 值不斷變化.
同時: 使用變量,將會使sql語句的結果不緩存.
8.9 子查詢優化
MySQL從4.1版本開始支持子查詢,使用子查詢進行SELECT語句嵌套查詢,可以一次完成很多邏輯上需要多個步驟才能完成的SQL操作。
子查詢雖然很靈活,但是執行效率並不高。
執行子查詢時,MYSQL需要創建臨時表,查詢完畢後再刪除這些臨時表,所以,子查詢的速度會受到一定的影響。
優化:
可以使用連接查詢(JOIN)代替子查詢,連接查詢時不需要建立臨時表,其速度比子查詢快。
Rbac-----兩種SQL語句
查詢語句優化
1: sql語句的時間花在哪兒?
答: 等待時間, 執行時間.
這兩個時間並非孤立的, 如果單條語句執行的快了,對其他語句的鎖定的也就少了
所以,我們來分析如何降低執行時間.
2: sql語句的執行時間,又花在哪兒了?
答:
a: 查----> 沿著索引查,甚至全表掃描
b: 取----> 查到行後,把數據取出來(sending data)
3: sql語句的優化思路?
答: 不查, 通過業務邏輯來計算,
比如論壇的註冊會員數,我們可以根據前3個月統計的每天註冊數, 用程序來估算.
少查, 儘量精準數據,少取行. 我們觀察新聞網站,評論內容等,一般一次性取列表10-30條左右.
必須要查,儘量走在索引上查詢行.
取時, 取儘量少的列.
比如select * from tableA, 就取出所有列, 不建議.
比如select * from tableA,tableB, 取出A,B表的所有列.
4: 如果定量分析查的多少行,和是否沿著索引查?
答: 用explain來分析
8.1 數據庫優化概述
2.1.1 什麼是優化?
l 合理安排資源、調整系統參數使MySQL運行更快、更節省資源。
l 優化是多方面的,包括查詢、更新、服務器等。
l 原則:減少系統瓶頸,減少資源佔用,增加系統的反應速度。
2.1.2 數據庫性能參數
l 使用SHOW STATUS語句查看MySQL數據庫的性能參數
• SHOW STATUS LIKE 'value‘
l 常用的參數:
• Slow_queries 慢查詢次數
• Com_(CRUD) 操作的次數
• Uptime 上線時間
8.2 EXPLAIN
在MySQL中可以使用EXPLAIN查看SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
2.1.1 id
SELECT識別符。這是SELECT查詢序列號。這個不重要。
代表select 語句的編號, 如果是連接查詢,表之間是平等關係, select 編號都是1,從1開始. 如果某select中有子查詢,則編號遞增.
2.1.2 select_type
表示SELECT語句的類型。有以下幾種值:
1、 SIMPLE表示簡單查詢,其中不包含連接查詢和子查詢。
2、 PRIMARY表示主查詢,或者是最外面的查詢語句。
3、 UNION表示連接查詢的第2個或後面的查詢語句。
4、 DEPENDENT UNIONUNION中的第二個或後面的SELECT語句,取決於外面的查詢。
5、 UNION RESULT連接查詢的結果。
6、 SUBQUERY子查詢中的第1個SELECT語句。
7、 DEPENDENT SUBQUERY子查詢中的第1個SELECT語句,取決於外面的查詢。
8、 DERIVEDSELECT(FROM 子句的子查詢)。
2.1.3 table
表示查詢的表。
有可能是
實際的表名如select * from t1;
表的別名如select * from t2 as tmp;
derived 如from型子查詢時
null 直接計算得結果,不用走表
2.1.4 type(重要)
表示表的連接類型。
以下的連接類型的順序是從最佳類型到最差類型:
1、 system表僅有一行,這是const類型的特列,平時不會出現,這個也可以忽略不計。
2、 const數據表最多隻有一個匹配行,因為只匹配一行數據,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
3、 eq_refmysql手冊是這樣說的:"對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY"。eq_ref可以用於使用=比較帶索引的列。
4、 ref查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
5、 ref_or_null該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
上面這五種情況都是很理想的索引使用情況。
6、 index_merge該聯接類型表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
7、 unique_subquery該類型替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
8、 index_subquery該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
9、 range只檢索給定範圍的行,使用一個索引來選擇行。
10、 index該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
11、 ALL對於每個來自於先前的表的行組合,進行完整的表掃描。(性能最差)
2.1.5 possible_keys
可能用到的索引
注意: 系統估計可能用的幾個索引,但最終,只能用1個
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列創建索引來提供性能。
2.1.6 key
最終用的索引.顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
2.1.7 key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
使用的索引的最大長度
type列: 是指查詢的方式, 非常重要,是分析”查數據過程”的重要依據
可能的值
all: 意味著從表的第1行,往後,逐行做全表掃描.,運氣不好掃描到最後一行.
index: 比all性能稍好一點,
通俗的說: all 掃描所有的數據行,相當於data_all index 掃描所有的索引節點,相當於index_all
2.1.8 ref
顯示使用哪個列或常數與key一起從表中選擇行。
2.1.9 rows
顯示MySQL認為它執行查詢時必須檢查的行數。
2.1.10 Extra
該列包含MySQL解決查詢的詳細信息
•Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜索更多的行。
•Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
•range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
•Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
•Using index:從只使用索引樹中的信息而不需要進一步搜索讀取實際的行來檢索表中的列信息。
•Usingtemporary:為了解決查詢,MySQL需要創建一個臨時表來容納結果。
•Using where:WHERE 子句用於限制哪一個行匹配下一個表或發送到客戶。
•Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何為index_merge聯接類型合併索引掃描。
•Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜索硬盤訪問實際的表。
8.3 in 型子查詢引出的陷阱
改進: 用連接查詢來代替子查詢
exists子查詢
優化1: 在group時, 用帶有索引的列來group, 速度會稍快一些,另外,
用int型比char型分組,也要快一些.(見37)
優化2: 在group時, 我們假設只取了A表的內容,group by 的列,儘量用A表的列,
會比B表的列要快.
優化3: 從語義上去優化
8.4 from 型子查詢:
注意::內層from語句查到的臨時表, 是沒有索引的.
所以: from的返回內容要儘量少.
奇技淫巧!
min/max優化在表中,一般都是經過優化的. 如下地區表
我們查min(id), id是主鍵,查Min(id)非常快.
但是,pid上沒有索引, 現在要求查詢3113地區的min(id);
select min(id) from it_area where pid=69;
試想id是有順序的,(默認索引是升續排列), 因此,如果我們沿著id的索引方向走,
那麼第1個pid=69的索引結點,他的id就正好是最小的id.
select id from it_area use index(primary) where pid=69 limit 1;
| 12 | 0.00128100 | select min(id) from it_area where pid=69 |
| 13 | 0.00017000 | select id from it_area use index(primary) where pid=69 limit 1 |
改進後的速度雖然快,但語義已經非常不清晰,不建議這麼做,僅僅是實驗目的.
8.5 count() 優化
誤區:
1:myisam的count()非常快
答: 是比較快,.但僅限於查詢表的”所有行”比較快, 因為Myisam對行數進行了存儲.
一旦有條件的查詢, 速度就不再快了.尤其是where條件的列上沒有索引.
2: 假如,id<100的商家都是我們內部測試的,我們想查查真實的商家有多少?
select count(*) from lx_com where id>=100; (1000多萬行用了6.X秒)
小技巧:
select count(*) from lx_com; 快
select count(*) from lx_com where id<100; 快
select count(*) frol lx_com -select count(*) from lx_com where id<100; 快
select (select count(*) from lx_com) -(select count(*) from lx_com where id<100)
8.6 group by
注意:
1:分組用於統計,而不用於篩選數據.
比如: 統計平均分,最高分,適合, 但用於篩選重複數據,則不適合.
以及用索引來避免臨時表和文件排序
2: 以A,B表連接為例,主要查詢A表的列,
那麼group by ,order by 的列儘量相同,而且列應該顯示聲明為A的列
8.7 union優化
注意: union all 不過濾效率提高,如非必須,請用union all
因為union去重的代價非常高, 放在程序裡去重.
limit 及翻頁優化
limit offset,N, 當offset非常大時, 效率極低,
原因是mysql並不是跳過offset行,然後單取N行,
而是取offset+N行,返回放棄前offset行,返回N行.
效率較低,當offset越大時,效率越低
優化辦法:
1: 從業務上去解決
辦法: 不允許翻過100頁
以百度為例,一般翻頁到70頁左右.
1:不用offset,用條件查詢.
3: 非要物理刪除,還要用offset精確查詢,還不限制用戶分頁,怎麼辦?
分析: 優化思路是不查,少查,查索引,少取.
我們現在必須要查,則只查索引,不查數據,得到id.
再用id去查具體條目. 這種技巧就是延遲索引.
8.8 巧用變量
1:用變量排名
例: 以ecshop中的商品表為例,計算每個欄目下的商品數,並按商品數排名.
select cat_id,count(*) as cnt from goods group by cat_id order by cnt desc;
並按商品數計算這些欄目的名次
set @curr_cnt := 0,@prev_cnt := 0, @rank := 0;
select cat_id, (@curr_cnt := cnt) as cnt,
(@rank := if(@curr_cnt <> @prev_cnt,@rank+1,@rank)) as rank,
@prev_cnt := @curr_cnt
from ( select cat_id,count(*) as cnt from shop. goods group by shop. goods.cat_id order by cnt desc) as tmp;
2:用變量計算真正影響的行數
當插入多條,當主鍵重複時,則自動更新,這種效果,可以用insert on duplication for update
要統計真正”新增”的條目, 如下圖,我們想得到的值是”1”,即被更新的行數
insert into user (uid,uname) values (4,’ds’),(5,'wanu'),(6,’safdsaf’)
on duplicate key update uid=values(uid)+(0*(@x:=@x+1)) , uname=values(uname);
mysql> set @x:=0;
Query OK, 0 rows affected (0.00 sec)
總影響行數-2*實際update數, 即新增的行數.
3: 簡化union
比如有新聞表,news , news_hot,
new_hot是一張內存表,非常快,用來今天的熱門新聞.
首頁取新聞時,邏輯是這樣的:
先取hot, 沒有再取news,為了省事,用一個union來完成.
select nid,title from news_hot where nid=xxx
union
select nid,title from news where nid=xxx;
如何利用變量讓後半句select不執行,
select id,content,(@find := 1) from news where id=1
union
select id,content,(@find :=1) from news2 where id=1 and (@find <= 0)
union 1,1,1 where (@find :=null) is not null;
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
3:小心變量的順序
如下圖:變量先在where中發揮作用,然後再是select操作.
如果where不成立,select操作再不發生.
Eg;
在這個例子中, 1,2兩行,先排好序, 在內存中,就是這樣的順序[2] [1]
再逐行where條件判斷,取值.
對比這2張圖,分析:
1: where先發揮作用,把需要的行都給找出
2: 然後再逐行select
因此, 前者, 最終select時,select@num變量,都是一個值
後者,不斷select,不斷修改@num的值, 值不斷變化.
同時: 使用變量,將會使sql語句的結果不緩存.
8.9 子查詢優化
MySQL從4.1版本開始支持子查詢,使用子查詢進行SELECT語句嵌套查詢,可以一次完成很多邏輯上需要多個步驟才能完成的SQL操作。
子查詢雖然很靈活,但是執行效率並不高。
執行子查詢時,MYSQL需要創建臨時表,查詢完畢後再刪除這些臨時表,所以,子查詢的速度會受到一定的影響。
優化:
可以使用連接查詢(JOIN)代替子查詢,連接查詢時不需要建立臨時表,其速度比子查詢快。
Rbac-----兩種SQL語句