本文主要考察兩個問題:
- 當某一列有爲null值的數據時,該列的索引是否還能生效
- is null或者is not null是否能使用到索引
首先貼上幾段官方文檔:
You can add an index on a column that can have NULL
values if you are using the MyISAM
, InnoDB
, or MEMORY
storage engine. Otherwise, you must declare an indexed column NOT NULL
, and you cannot insert NULL
into the column.
大意是:如果你選擇了MyISAM
, InnoDB
, or MEMORY
這幾個引擎,那麼你可以爲允許null值的字段加上索引,如果不是這幾個引擎,那麼只能爲那些not null的字段加上索引,這些字段也無法保存null值。
MySQL can perform the same optimization on col_name
IS NULL
that it can use for col_name
=
constant_value
. For example, MySQL can use indexes and ranges to search for NULL
with IS NULL
.
大意是:mysql可以使用索引來查詢NULL字段。
下面開始測試
建表:a、b、c字段均接受null值
添加索引:
ALTER TABLE `j_copy` ADD INDEX (a);
爲問題1編寫查詢語句:
EXPLAIN select * from j_copy where a = 'a1';
解釋執行過程:
問題1結論:當某一列有爲null值的數據時,該列的索引依然生效
爲問題2編寫查詢語句:
1.EXPLAIN select * from j_copy where a is null;
2.EXPLAIN select * from j_copy where a is not null;
解釋執行過程:
1.
2.
情況1:
情況2:
問題2結論:
1.使用is null確實是走了索引,沒有問題。
2.現象比較特殊,在這裏is not null條件並沒有走索引,但是修改成select a from j_copy的話,就可以走索引了。一開始不太理解這個現象,網上翻了很多文章,找到了一個比較靠譜的說法:
select a from j_copy直接讀取索引上的數據後即可返回。而select * from j_copy如果走索引的話,則需要通過索引獲取數據位置再去讀取整行內容,在數據比較少的情況下,可能會更慢,所以mysql的優化器選擇了直接全表掃描。
爲了驗證上面內容,我又測試了一下,爲a、b、c三個字段添加聯合索引,那麼三個字段的數據都會保存在索引裏面,再執行語句:
以上實驗都是在字段接受null值的條件下做的實驗。在字段not null的情況下,is null和is not null都不會走索引。