想要好好寫sql需要知道的優化常識

一:sql語句的小技巧

1.使用group by 分組查詢時,默認分組後,還會排序,可能會降低速度,在group by 後面增加 order by null 就可以防止排序。

2.有些情況下,可以使用連接來替代子查詢。因爲使用join,MySQL不需要在內存中創建臨時表。

如:select * from dept, emp where dept.deptno=emp.deptno; 
// 替換成
select * from dept left join emp on dept.deptno=emp.deptno; 

二:分表技術

1.什麼情況下需要分表?

(1) 如果一個表的每條記錄的內容很大,那麼就需要更多的IO操作,如果字段值比較大,而使用頻率相對比較低,可以將大字段移到另一張表中,當查詢不查大字段的時候,這樣就減少了I/O操作;
(2)如果表的數據量非常非常大,那麼查詢就變的比較慢;也就是表的數據量影響到查詢的性能;
(3)表中的數據本來就有獨立性,例如分別記錄各個地區的數據或者不同時期的數據,特別是有些數據常用,而另外一些數據不常用;
 (4)  分表技術有兩種水平分割垂直分割

垂直分割

垂直分割是指數據表列的拆分,把一張表列比較多的表拆分爲多張表。垂直分割一般用於拆分大字段和訪問頻率低的字段,分離冷熱數據。

垂直分割比較常見:例如博客系統中的文章表,比如文章tbl_articles
(id, titile, summary, content, user_id, create_time),因爲文章中的內容content會比較長,放在tbl_articles中會嚴重影響表的查詢速度,所以將內容放到tbl_articles_detail(article_id, content),像文章列表只需要查詢tbl_articles中的字段即可。

垂直拆分的優點:可以使得行數據變小,在查詢時減少讀取的Block數,減少I/O次數。此外,垂直分區可以簡化表的結構,易於維護。

垂直拆分的缺點:主鍵會出現冗餘,需要管理冗餘列,並會引起join操作,可以通過在應用層進行join來解決。此外,垂直分區會讓事務變得更加複雜。

水平分割

水平拆分是指數據錶行數據的拆分,表的行數超過500萬行或者單表容量超過10GB時,查詢就會變慢,這時可以把一張的表的數據拆成多張表來存放。水平分表儘可能使每張表的數據量相當,比較均勻。

水平拆分會給應用增加複雜度,它通常在查詢是需要多個表名,查詢所有數據需要union操作。在許多數據庫應用中,這種複雜性會超過它帶來的優點。

因爲只要索引關鍵字不大,則在索引用於查詢時,表中增加2-3倍數據量,查詢時也就增加讀一個索引層的磁盤次數,所以水平拆分要考慮數據量的增長速度,根據實際情況決定是否需要對錶進行水平拆分。

水平分割最重要的是找到分割的標準,不同的表應根據業務找出不同的標準

  1. 用戶表可以根據用戶的手機號段進行分割如user151、user150、user153等,每個號段就是一張表

  2. 用戶表也可以根據用戶的id進行分割,加入分3張表user0,user1,user2,如果用戶的id%3=0就查詢user0表,
    如果用戶的id%3=1就查詢user1表

  3. 對於訂單表可以按照訂單的時間進行分

三:讀寫分離技術

實現mysql讀寫分離的前提是我們已經將mysql主從複製配置完畢,讀寫分離實現方式:
(1)配置多數據源。
(2)使用mysql的proxy中間件代理工具,如mysql-proxy等

前提條件:必須要部署主從複製。

主從複製的原理
mysql的主從複製和讀寫分離兩者有着緊密的聯繫,首先要部署主從複製,只有主從複製完成了才能在此基礎上進行數據的讀寫分離。

讀寫分離的原理
讀寫分離就是隻在主服務器上寫,只在從服務器上讀。基本原理是讓主數據庫處理事務性insert、update、delete查詢,而從服務器處理select查詢。數據庫複製用來把事務性查詢導致的變更同步到從數據庫中。

四:索引優化

索引分類

  • 普通索引:最基本的索引。

  • 組合索引:多個字段上建立的索引,能夠加速複合查詢條件的檢索。

  • 唯一索引:與普通索引類似,但索引列的值必須唯一,允許有空值。

  • 組合唯一索引:列值的組合必須唯一。

  • 主鍵索引:特殊的唯一索引,用於唯一標識數據表中的某一條記錄,不允許有空值,一般用primary key約束。

  • 全文索引:用於海量文本的查詢,MySQL5.6之後的InnoDB和MyISAM均支持全文索引。由於查詢精度以及擴展性不佳,更多的企業選擇Elasticsearch。

索引優化

  • 分頁查詢很重要,如果查詢數據量超過30%,MYSQL不會使用索引。

  • 單表索引數不超過5個、單個索引字段數不超過5個。

  • 字符串可使用前綴索引,前綴長度控制在5-8個字符。

  • 字段唯一性太低,增加索引沒有意義,如:是否刪除、性別。

合理使用覆蓋索引,如下所示:

select login_name, nick_name from member where login_name = ?

login_name, nick_name兩個字段建立組合索引,比login_name簡單索引要更快。、

五:操作符優化

操作符<>優化

通常<>操作符無法使用索引,舉例如下,查詢金額不爲100元的訂單:

select id from orders where amount != 100;

如果金額爲100的訂單極少,這種數據分佈嚴重不均的情況下,有可能使用索引。鑑於這種不確定性,採用union聚合搜索結果,改寫方法如下:

(select id from orders where amount > 100)
 union all
(select id from orders where amount < 100 and amount > 0)

OR優化

在Innodb引擎下or無法使用組合索引,比如:

select id,product_name from orders where mobile_no = '15321589999' or user_id = 100;

OR無法命中mobile_no + user_id的組合索引,可採用union,如下所示:

(select id,product_name from orders where mobile_no = '15321589999')
 union
(select id,product_name from orders where user_id = 100);

此時id和product_name字段都有索引,查詢才最高效。

IN優化

IN適合主表大子表小,EXIST適合主表小子表大。由於查詢優化器的不斷升級,很多場景這兩者性能差不多一樣了。

嘗試改爲join查詢,舉例如下:

select id from orders where user_id in (select id from user where level = 'VIP');

採用JOIN如下所示:

select o.id from orders o left join user u on o.user_id = u.id where u.level = 'VIP';

不做列運算

通常在查詢條件列運算會導致索引失效,如下所示:

查詢當日訂單

select id from order where date_format(create_time,'%Y-%m-%d') = '2019-01-01';

date_format函數會導致這個查詢無法使用索引,改寫後:

select id from order where create_time between '2019-01-01 00:00:00'

Like優化

like用於模糊查詢,舉個例子(field已建立索引):

SELECT column FROM table WHERE field like '%keyword%';

這個查詢未命中索引,換成下面的寫法:

SELECT column FROM table WHERE field like 'keyword%';

去除了前面的%查詢將會命中索引,但是產品經理一定要前後模糊匹配呢?全文索引fulltext可以嘗試一下,但Elasticsearch纔是終極武器。

Join優化

join的實現是採用Nested Loop Join算法,就是通過驅動表的結果集作爲基礎數據,通過該結數據作爲過濾條件到下一個表中循環查詢數據,然後合併結果。如果有多個join,則將前面的結果集作爲循環數據,再次到後一個表中查詢數據。

驅動表和被驅動表儘可能增加查詢條件,滿足ON的條件而少用where,用小結果集驅動大結果集。
被驅動表的join字段上加上索引,無法建立索引的時候,設置足夠的Join Buffer Size。
禁止join連接三個以上的表,嘗試增加冗餘字段。

其他數據庫

作爲一名後端開發人員,不但要精通關係型數據庫,同時也要積極關注NoSQL非關係型數據庫,他們已經足夠成熟並被廣泛採用,能解決特定場景下的性能瓶頸。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章