在MySQL中,有一些語句即使邏輯相同,執行起來的性能差異確實極大的。
先拋出一個結論:如果想使用索引樹搜索功能,就不能使用數據庫函數來處理索引字段值,而是在不改變索引字段值的同時,自己通過SQL語句來實現邏輯
條件字段函數操作
假設我們現在維護了一張系統交易表:
mysql> CREATE TABLE `tradelog` ( `id` int(11) NOT NULL, `tradeid` varchar(32) DEFAULT NULL, `operator` int(11) DEFAULT NULL, `t_modified` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `tradeid` (`tradeid`), KEY `t_modified` (`t_modified`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
我們在表中插入5條測試數據:
insert into tradelog (id,tradeid,t_modified) values(1,'a','2017-03-15'); insert into tradelog (id,tradeid,t_modified) values(2,'b','2017-06-11'); insert into tradelog (id,tradeid,t_modified) values(3,'c','2017-07-03'); insert into tradelog (id,tradeid,t_modified) values(4,'d','2018-08-11'); insert into tradelog (id,tradeid,t_modified) values(5,'e','2018-09-12');
SQL執行結果
接下來我們需要查詢2016年到2018年,所有7月份的數據。
SQL可以這樣寫:
select count(*) from tradelog where month(t_modified)=7;
我們可以通過explain命令,對這行語句的執行結果進行分析。
SQL執行結果
即該語句使用了t_modified索引,row=5,代表了該語句進行了全索引掃描,Using index表示使用了覆蓋索引。
那么為什么會這樣呢?
首先執行操作用哪個索引,是優化器決定的,這里可以使用的索引是主鍵索引和t_modified索引。在對比索引樹大小后發現,t_modified索引樹更小,所以優化器選擇使用t_modified索引,但是為什么還會使用全索引掃描,而不是索引樹查找的方式呢?原因是innodb索引樹查找的方式,是由於同級的兄弟節點具有順序性(類似於二分查找,要求數據有序),鎖索引值的順序性被破壞,優化器就只能選擇全索引掃描的方式執行語句,所以
對索引字段的函數操作,會破壞索引值的順序性,導致優化器放棄走索引樹搜索功能。
我們如果想使用索引樹搜索功能,就不能使用數據庫函數來處理索引字段值,而是在不改變索引字段值的同時,自己通過SQL語句來實現邏輯,上述SQL語句可做如下的改寫:
select count(*) from tradelog where (t_modified >= '2016-7-1' and t_modified<'2016-8-1') or (t_modified >= '2017-7-1' and t_modified<'2017-8-1') or (t_modified >= '2018-7-1' and t_modified<'2018-8-1');
接着我們使用explain對其進行分析:
SQL執行結果
此時我們可以看出,此時該語句采用了樹搜索的方式,只掃描了3行數據。