深入淺出Mysql - 優化篇(Sql語句)

定期優化表

如果已經刪除了表的一大部分,或者如果已經對含有可變長度行的表(含有VARCHAR、BLOB或TEXT列的表)進行了很多更改,則應使用OPTIMIZE TABLE命令來進行表優化。?這個命令可以將表中的空間碎片進行合併,並且可以消除由於刪除或者更新造成的空間浪費,但OPTIMIZE TABLE命令只對MylSAM、BDB和InnoDB表起作用。

mysql> analyze table fa_order;
+------------------------+---------+----------+----------+
| Table                  | Op      | Msg_type | Msg_text |
+------------------------+---------+----------+----------+
| zs_personcash.fa_order | analyze | status   | OK       |
+------------------------+---------+----------+----------+
1 row in set (0.03 sec)

對於InnoDB引擎的表來說,通過設置innodb_file_per_table參數,設置InnoDB爲獨立表空間模式,這樣每個數據庫的每個表都會生成一個宓立的雲1文件,用於存儲表的數據和索引,這樣可以一定程度上減輕InnoDB表的空間回收問題。另外,在刪除大量數據後,InnoDB表可以通過alter table但是不修改引擎的方式來回收不用的空間。

常用的SQL優化

優化Insert語句

  • 如果同時從同一客戶插入很多行,應盡*使用多個值表的INSERT諾句,這種方式將大大編減客戶端與數據庫之間的連接、關閉等消耗,使得效率比分開執行的單個INSERT語句?快(在大部分情況下,使用多個值表的INSERT語句能比單個INSERT語句快上好幾倍)。
	insert into table ( name , age , sex ) values ( 'stark', 30 , 1), ( 'yy', 30 , 2 ) ...
  • 如果從不同客戶指入很多行,可以通過使用INSERT DELAYED#句得到更高的速度.?DELAYED的舍義是讓INSERT語句馬上執行,其實數據都敬放在內存的隊列中,並沒冇真正寫入磁盤,這比毎條語句分別括入要快得多;LOW_PRIORITY R1好相反,在所有算他用戶時表的讀寫完成後才進行插入。
  • 將索引文件和數據文件分在不同的磁盤上存放(利用建表中的選項)。
  • 如果進行批量插入,可以通過增加bulk_insert_buflfer_size變量值的方法來提高速度,但是,這隻能對MylSAM表使用。
  • 當從一個文本丈件裝載一個表時,使用LOAD DATA INFILE.這通常比使用很多INSERT語句快20倍。

優化Order By 語句

優化ORDER BY語句之前,首先來了解一下MySQL中的排序方式。

mysql> show index from fa_order;
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name     | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| fa_order |          0 | PRIMARY      |            1 | id           | A         |     5080802 | NULL     | NULL   |      | BTREE      |         |               |
| fa_order |          1 | pay_status   |            1 | pay_status   | A         |          18 | NULL     | NULL   | YES  | BTREE      |         |               |
| fa_order |          1 | goodtype     |            1 | goodtype     | A         |          18 | NULL     | NULL   | YES  | BTREE      |         |               |
| fa_order |          1 | user_id      |            1 | user_id      | A         |     5080802 | NULL     | NULL   |      | BTREE      |         |               |
| fa_order |          1 | flag         |            1 | flag         | A         |          18 | NULL     | NULL   | YES  | BTREE      |         |               |
| fa_order |          1 | ordersn      |            1 | order_no     | A         |     5080802 | NULL     | NULL   | YES  | BTREE      |         |               |
| fa_order |          1 | consume_type |            1 | consume_type | A         |          18 | NULL     | NULL   | YES  | BTREE      |         |               |
| fa_order |          1 | f_addtime    |            1 | addtime      | A         |     1016160 | NULL     | NULL   | YES  | BTREE      |         | 查詢統計錢    |
| fa_order |          1 | f_addtime    |            2 | flag         | A         |     1016160 | NULL     | NULL   | YES  | BTREE      |         | 查詢統計錢    |
+----------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
9 rows in set (0.06 sec)

第一種通過有序索引順序掃描直接返回有序數據,這種方式在使用explain分析査詢的時候顯示爲Using Index,不需要額外的排序,操作效率較高。

mysql> explain select id from fa_order order by id;
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table    | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
|  1 | SIMPLE      | fa_order | index | NULL          | PRIMARY | 8       | NULL | 5080802 | Using index |
+----+-------------+----------+-------+---------------+---------+---------+------+---------+-------------+
1 row in set (0.06 sec)

第二種是通過對返回數據進行排序,也就是通常說的Filesort排序,所有不是通過索引直接返回排序結果的排序都叫Filesort排序。Filesort並不代表通過磁盤文件進行排序,而只是說明進行了Filesort排序操作,至於排序操作是否使用了磁盤文件或臨時表等,則取決於MySQL服務器對排序參數的設置和需要排序數據的大小。

mysql> explain select * from fa_order order by goodtype;
+----+-------------+----------+------+---------------+------+---------+------+---------+----------------+
| id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra          |
+----+-------------+----------+------+---------------+------+---------+------+---------+----------------+
|  1 | SIMPLE      | fa_order | ALL  | NULL          | NULL | NULL    | NULL | 5080802 | Using filesort |
+----+-------------+----------+------+---------------+------+---------+------+---------+----------------+
1 row in set (0.05 sec)

Filesort是通過相應的排序算法,將取得的數據在sort_buffer_size系統變量設置的內存排序區中進行排序,如果內存裝載不下,它就會將磁盤上的魏進行分塊,再對各個數據塊進行排序,然後將各個塊合併成有序的結果集。sort_bufifer_size設置的排序區是每個線程獨佔的,所以同一個時刻,MySQL中存在多個sort buff排序區。

瞭解了MySQL排序的方式,優化目標就清晰了:儘量減少額外的排序,通過索引直接返回有序數據。WHERE條件和ORDER BY使用相同的索引,並且ORDER BY的順序和索引順序相同,並且ORDER BY的字段都是升序或者都是降序。否則肯定需要額外的排序操作,這樣就會出現Filesort。

Filesort 的優化

通過創建合適的索引能夠減少Filesort出現,但是在某些情況下,條件限制不能讓Filesort消失,那就需要想辦法加快Filesort的操作。對於Filesort, MySQL有兩種排序算法。

兩次掃描算法(Two Passes):首先根據條件取出排序字段和行指針信息,之後在排序?區sort buffer中排序如果排序區sort buffer不夠,則在臨時表Temporary Table中存儲排序結果.完成排序後根據行指針回表讀取記錄.該算法是MySQL4.1之前採用的算法,需要兩次訪問數據,第一次獲取排序字段和行指針信息,第二次根據行指針獲取記錄,尤其是第二次讀取操作可能導致大量隨機I/O操作;優點是排序的時候內存開銷較少。

一次掃描算法(Single Pass): 一次性取出満足條件的行的所有字段,然後在排序區sort buffer中排序後直接輸出結果集.排序的時候內存開銷比較大,但是排序效率比兩次掃描算法美高。

MySQL通過比較系統變量max_lengfli_for_sort_data的大小和Query語句取出的字段總大小來判斷使用哪種排序算法。如果max_length_for_sort_data更大,那麼使用第二種優化之後的算法;否則使用第一種算法。

適當加大系統變量max_length_fbr_sort_data的值,能夠讓MySQL選擇更優化的Filesort排序算法。當然,假如max_length_fdr_sort_data設置過大,會造成CPU利用率過低和磁盤I/O?過高,CPU和I/O利用平衡就足夠了。

適當加大sort_buffer_size排序區,儘量讓排序在內存中完成,而不是通過創建臨時表放在文件中進行;當然屈不能無限制加大sort_buflfer_size排序區,因爲sort_buffbr_size參數是每個線程獨佔的,設置過大,會導致服務器SWAP要考慮數據庫活動連接成和服務器內存的?大小來適當設置排序區。

儘量只使用必要的字段,SELECT具體的字段名稱,而不是SELECT*選擇所有字段,這樣可以減少排序區的使用,提高SQL性能。

優化Group By 語句

默認情況下,MySQL對所有GROUP BY coll,col2,…的字段進行排序。這與在査詢中指定 ORDER BY coll,co!2,…類似。因此,如果顯式包括包含相同列的ORDER BY子句,則對MySQL的實際執行性能沒有什麼影響。

如果査詢包括GROUP BY但用戶想要避免排序結果的消耗測可以指定ORDER BY NULL 禁止排序。

優化嵌套查詢

MySQL 4.1開始支持SQL的子査詢。這個技術可以使用SELECT語句來創建一個單列的?査詢結果,然後把這個結果作爲過濾條件用在另一個査詢中。使用子査詢可以一次性地完成很多邏輯上需要多個步驟才能完成的SQL操作,同時也可以避免事務或者表鎖死,並且寫起來也很容易。但是,有些情況下,子査詢可以被更有效率的連接(JOIN)替代。

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