1. 禁止使用SELECT *,只獲取必要的字段,須要顯示說明列屬性mysql
解讀:sql
a)讀取不須要的列會增長CPU、IO、NET消耗數據庫
b)不能有效的利用覆蓋索引緩存
c)使用SELECT *容易在增長或者刪除字段後出現程序BUG架構
2. 禁止使用INSERT INTO t_xxx VALUES(xxx),必須顯示指定插入的列屬性函數
解讀:容易在增長或者刪除字段後出現程序BUG工具
3. 禁止使用屬性隱式轉換性能
解讀:SELECT uid FROM t_user WHERE phone=13812345678 會致使全表掃描,而不能命中phone索引,猜猜爲何?(這個線上問題不止出現過一次)測試
4. 禁止在WHERE條件的屬性上使用函數或者表達式,在屬性上進行計算不能命中索引優化
解讀:SELECT uid FROM t_user WHERE from_unixtime(day)>='2017-02-15' 會致使全表掃描
正確的寫法是:SELECT uid FROM t_user WHERE day>= unix_timestamp('2017-02-15 00:00:00')
例如:
select * from order where YEAR(date) < = '2017'
即便date上創建了索引,也會全表掃描,可優化爲值計算:
select * from order where date < = CURDATE()
或者:
select * from order where date < = '2017-01-01'
5. 禁止負向查詢,以及%開頭的模糊查詢。
解讀:
a)負向查詢條件:NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等,會致使全表掃描
b)%開頭的模糊查詢,會致使全表掃描
6. 禁止大表使用JOIN查詢,禁止大表使用子查詢
解讀:會產生臨時表,消耗較多內存與CPU,極大影響數據庫性能
7. 禁止使用OR條件,必須改成IN查詢
解讀:舊版本Mysql的OR查詢是不能命中索引的,即便能命中索引,爲什麼要讓數據庫耗費更多的CPU幫助實施查詢優化呢?
8. 應用程序必須捕獲SQL異常,並有相應處理
9. 負向條件查詢不能使用索引
select * from order where status!=0 and stauts!=1
not in/not exists都不是好習慣
能夠優化爲in查詢:
select * from order where status in(2,3)
10. 前導模糊查詢不能使用索引
select * from order where desc like '%XX'
而非前導模糊查詢則能夠:
select * from order where desc like 'XX%'
11. 數據區分度不大的字段不宜使用索引
select * from user where sex=1
緣由:性別只有男,女,每次過濾掉的數據不多,不宜使用索引。
經驗上,能過濾80%數據時就可使用索引。對於訂單狀態,若是狀態值不多,不宜使用索引,若是狀態值不少,可以過濾大量數據,則應該創建索引。
12. limit高效分頁
limit越大,效率越低
select id from t limit 10000, 10;
應該改成 =>
select id from t where id > 10000 limit 10;
13. 若是業務大部分是單條查詢,使用Hash索引性能更好,例如用戶中心
select * from user where uid=?
select * from user where login_name=?
緣由:
B-Tree索引的時間複雜度是O(log(n))
Hash索引的時間複雜度是O(1)
14. 容許爲null的列,查詢有潛在大坑
單列索引不存null值,複合索引不存全爲null的值,若是列容許爲null,可能會獲得「不符合預期」的結果集
select * from user where name != 'shenjian'
若是name容許爲null,索引不存儲null值,結果集中不會包含這些記錄。
因此,請使用not null約束以及默認值。
15. 複合索引最左前綴,並非值SQL語句的where順序要和複合索引一致
用戶中心創建了(login_name, passwd)的複合索引
select * from user where login_name=? and passwd=?
select * from user where passwd=? and login_name=?
都可以命中索引
select * from user where login_name=?
也能命中索引,知足複合索引最左前綴
select * from user where passwd=?
不能命中索引,不知足複合索引最左前綴
16. 若是明確知道只有一條結果返回,limit 1可以提升效率
select * from user where login_name=?
能夠優化爲:
select * from user where login_name=? limit 1
緣由:
你知道只有一條結果,但數據庫並不知道,明確告訴它,讓它主動中止遊標移動
17. 把計算放到業務層而不是數據庫層,除了節省數據的CPU,還有意想不到的查詢緩存優化效果
select * from order where date < = CURDATE()
這不是一個好的SQL實踐,應該優化爲:
$curDate = date('Y-m-d');
$res = mysql_query(
'select * from order where date < = $curDate');
緣由:
釋放了數據庫的CPU
屢次調用,傳入的SQL相同,才能夠利用查詢緩存
18. 強制類型轉換會全表掃描
select * from user where phone=13800001234
你覺得會命中phone索引麼?大錯特錯了,這個語句究竟要怎麼改?
正確查詢:
select * from user where phone='13800001234'
加上引號,保持類型一直,避免隱式類型轉換
19. union all 確定是可以命中索引的,簡單的in可以命中索引,對於or,新版的MySQL可以命中索引,對於!=,負向查詢確定不能命中索引
20. 分批批量更新
21. 使用union all替代union,union有去重開銷
22. 務必請使用「同類型」進行比較,不然可能全表掃面
23. ORDER BY 後面的列默認按升序排序,若是須要指定列的排序規則,須要每一個列單獨指定。例如:若是想在多個列上進行降序,必須對每一列
指定DESC關鍵字。ORDER BY prode_pice DESC,prod_name DESC;
24. 不等於,不會返回符合條件的null值。
25. 在UPDATE或DELETE語句使用WHERE子句前,應該先用SELECT 進行測試,保證它過濾的是正確的記錄,以防編寫的WHERE子句不正確。
有的DBMS容許數據庫管理員施加約束,防止執行不帶WHERE子句的UPDATE或DELETE語句。若是所採用的DBMS支持這個特性,應該使用它。
26. MySQL在Linux下數據庫名、表名、列名、別名大小寫規則是這樣的:
1).數據庫名與表名是嚴格區分大小寫的;
2).表的別名是嚴格區分大小寫的;
3).列名與列的別名在全部的狀況下均是忽略大小寫的;
4).變量名也是嚴格區分大小寫的;
列名與列的別名在全部的狀況下均是忽略大小寫的。
表的別名是區分大小寫的。下面的查詢將不能工做,由於它用 a 和 A 引用別名:
mysql> SELECT col_name FROM tbl_name AS a WHERE a.col_name = 1 OR A.col_name = 2;
27. Mysql默認的字符檢索策略:utf8_general_ci,表示不區分大小寫;utf8_general_cs表示區分大小寫,utf8_bin表示二進制比較,一樣也區分大小寫 。
(注意:在Mysql5.6.10版本中,不支持utf8_genral_cs!!!!)
操做數據庫前先備份!
學會使用新能分析工具
show profile;
mysqlsla;
mysqldumpslow;
explain;
show slow log;
show processlist;
show query_response_time(percona)