SQL优化之浅见
SQL優化之淺見
- 一、查詢優化
- 二、導入大量數據時的優化
- 三、INSERT優化
- 四、字段注釋
- 五、說明
用了段mysql/Oracle/hive等數據庫,對SQL語言以Mysql為例,總結一下對sql優化方面的見解,歡迎大家補充。
一、查詢優化
1.在關聯查詢中,關聯鍵的數據類型一定要相同,最常見的是字符串類型的數字被當作INT類型與INT類型的鍵進行關聯,隱性類型轉換會使性能受到很大影響。
2.模糊查詢使用LIKE時盡量不使用左側模糊,比如“%其實也厲害”,“%其實%”,不如使用右側模糊查詢,如:“軟輔其實也%”;
3.在關聯或者WHERE條件中,盡量不要對等號左側的字段進行任何處理,以免索引失效,如將8位數字類型的字段轉換為日期:
4.如果可以,請限制大表的數據量,包括過濾無效、無意義數據,合理分區等;
5.落表也是一種很好的辦法。
6.添加索引,優先考慮where/group by 使用的字段。
7.where條件中注意避免索引失效。
8.合理分區;
9.數據更新一般delete+insert into方式要比update等更新方式要快的多。
10.in 和 exists性能比較:
以哪個表為驅動表就會優先使用哪個表的索引,所以如果外層表較大,內層表較小,我們一般使用in;反之使用exists,這樣我們會用到內層表(大表)的索引列;(其實后來的優化器中,如果兩種方法都會使用外層表做為驅動,具體還要看執行計劃.)
外表大,用in; 內表大,用exists;現在,雖然優化器的不斷完善,兩者在相同情況下執行是一樣的,都會使用子查詢的索引。如下:
mysql> EXPLAIN SELECT * FROM user_buy_product_dtl_f WHERE CNAME IN (SELECT PNAME FROM later_fo_word_record_f ); +----+--------------------+------------------------+----------------+---------------+------------+---------+------+---------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+------------------------+----------------+---------------+------------+---------+------+---------+--------------------------+ | 1 | PRIMARY | user_buy_product_dtl_f | ALL | NULL | NULL | NULL | NULL | 1016485 | Using where | | 2 | DEPENDENT SUBQUERY | later_fo_word_record_f | index_subquery | name_index | name_index | 63 | func | 3 | Using index; Using where | +----+--------------------+------------------------+----------------+---------------+------------+---------+------+---------+--------------------------+ 2 rows in set (0.00 sec)mysql> EXPLAIN SELECT * FROM later_fo_word_record_f WHERE PNAME IN (SELECT CNAME FROM user_buy_product_dtl_f ); +----+--------------------+------------------------+----------------+---------------+-------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+------------------------+----------------+---------------+-------------+---------+------+------+--------------------------+ | 1 | PRIMARY | later_fo_word_record_f | ALL | NULL | NULL | NULL | NULL | 36 | Using where | | 2 | DEPENDENT SUBQUERY | user_buy_product_dtl_f | index_subquery | name_indexc | name_indexc | 63 | func | 641 | Using index; Using where | +----+--------------------+------------------------+----------------+---------------+-------------+---------+------+------+--------------------------+ 2 rows in set (0.00 sec)mysql> EXPLAIN SELECT * FROM user_buy_product_dtl_f F WHERE EXISTS (SELECT 1 FROM later_fo_word_record_f T WHERE F.CNAME = T.PNAME ); +----+--------------------+-------+------+---------------+------------+---------+--------------+---------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+-------+------+---------------+------------+---------+--------------+---------+--------------------------+ | 1 | PRIMARY | F | ALL | NULL | NULL | NULL | NULL | 1016485 | Using where | | 2 | DEPENDENT SUBQUERY | T | ref | name_index | name_index | 63 | test.F.CNAME | 3 | Using where; Using index | +----+--------------------+-------+------+---------------+------------+---------+--------------+---------+--------------------------+ 2 rows in set (0.00 sec)mysql> EXPLAIN SELECT * FROM later_fo_word_record_f F WHERE EXISTS (SELECT 1 FROM user_buy_product_dtl_f T WHERE F.PNAME = T.CNAME ); +----+--------------------+-------+------+---------------+-------------+---------+--------------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+-------+------+---------------+-------------+---------+--------------+------+--------------------------+ | 1 | PRIMARY | F | ALL | NULL | NULL | NULL | NULL | 36 | Using where | | 2 | DEPENDENT SUBQUERY | T | ref | name_indexc | name_indexc | 63 | test.F.PNAME | 641 | Using where; Using index | +----+--------------------+-------+------+---------------+-------------+---------+--------------+------+--------------------------+ 2 rows in set (0.00 sec)但是not in和not exists就不一樣了:
not in 會對內外表進行全表掃描,不會用到索引; not exists 依然會用到子查詢的索引;所以not in的效率往往不如not exists.
然而實際操作中,未必是這樣的,也可能兩種語法中都會使用子查詢的表索引,如下later_fo_word_record_f為小表,user_buy_product_dtl_f為大表,執行計劃為:
11.union all
如果union all要優化的話,落個臨時表吧,insert into效率還是不錯的。
12.union all 與 union
眾所周知,union 包含有去重操作,而union all沒有,但
在大數據量的情況下distinct + union all 性能大于 UNION 的性能。
當然,如果確認沒有重復記錄,直接用union all就OK了。
13.有子查詢的group by 字段數和group by數都要盡量少。
14.盡量避免使用select *,無效字段會影響查詢效率。
15.盡量避免空值判斷
空值判斷會使引擎放棄索引進行全表掃描,因而降低查詢效率。
Mysql中字段要求盡量設置為not null,可以用0或’'代替設計的表模型中的Null;
一定要注意‘’與null的區別:
16.避免使用or,會使索引失效,可以使用union all代替。
17數據量較大時,避免使用where 1=1,雖然便于拼接,但也會導致索引失效。
二、導入大量數據時的優化
1.MylSAM引擎的表可以使用DISABLE KEYS/ENABLE KEYS來打開表非唯一索引校驗:
alter table t1 DISABLE KEYS; loading data... alter table t1 ENABLE KEYS;2.InnoDB引擎插入數據前可以提前對自增長主鍵排序,也會提高數據導入效率。
3.InnoDB引擎開關唯一性校驗:
4.InnoDB引擎開關自動提交:
SET AUTOCOMMIT =0; SET AUTOCOMMIT =1;三、INSERT優化
多值插入比每個insert插入一個值的連接次數要少很多,因此多值插入比多個insert插入要快。
四、字段注釋
如果節點性能超級差,在建表時盡量把陪伴我的注釋放在ddl語句內,這樣只需要連接一次。而注釋在DDL之外會連接多次。
五、說明
這也只是我在平時工作中的一些技巧總結,實際的優化還是要根據日志來對慢sql優化,比如配置或物理存儲也會影響執行的性能。
總結
- 上一篇: VC char和TCHAR之间转换
- 下一篇: mysql查询姓王的信息代码_MySQL