SQL語句優化

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)

 

 

參見:58到家數據庫30條軍規解讀

         或許你不知道的10條SQL技巧

         MySQL的or/in/union與索引優化 | 架構師之路

         趕集mysql軍規

相關文章
相關標籤/搜索