數據庫聯合索引+空值的索引使用問題


昨天在QQ群里討論一個SQL優化的問題,語句大致如下:

select A,min(B) from table group by A;
--A,B都沒有not null約束,A列無空值,B列有空值。
--存在復合索引IX_TEST(A,B)

於是手動測試,先看Oracle,環境采用Oracle自帶的scott用戶下的emp表。

1.首先查看如下語句的執行計划(此時表只有主鍵索引):

2.添加IX_TEST(deptno,comm)后查看執行計划:

發現依然是全表掃描。

3.為deptno列添加非空約束后再次查看執行計划:

SQL Server的相關測試流程基本一致。

Tom在《Expert one on Oracle》中說:Oracle數據庫中,除位圖索引和聚簇索引外,單列Btree索引節點是不存儲空值的。聯合索引只要有一個列不為空,Btree節點就會存儲索引鍵值。

在本例中我們創建了(deptno,comm)的聯合索引,如果deptno沒有非空約束優化器選擇全表掃描,如果有非空約束優化器選擇索引全掃描。說明添加非空約束后Oracle認為所有的記錄都已經被包含在了索引中因此無需全表掃描。

因此在Oracle中一定要為聯合索引的首列設置非空約束。

4.MySQL測試

在MySQL中這個問題稍微復雜一點,因為MySQL的NULL值和空字符是有區別的,本文只測試innodb存儲引擎(MySQL5.7.22版本)。

首先把SCOTT的數據從oracle完全搞到MySQL,除了EMP表外其他3個表的使用navicat即可同步,EMP表由於HIREDATE的日期類型,需要先自己在MySQL端創建表然后使用PLSQL Developer導出SQL插入語句然后將其在MySQL端執行,如下是當前的EMP表數據:

創建索引后結果如下:

可見在Mysql Innodb中無論復合索引首列是否存在非空約束,都會使用索引,這點與Oracle不同。

那么innodb中如果索引中存在NULL值,還會使用索引嗎?繼續測試:

 

可以看到存在NULL值,innodb也會走索引,那么空字符呢?

繼續測試發現無論字符類型的列中存儲的是NULL還是空字符''都是會走索引的。

在3大關系型數據庫中,B+tree索引結構最為明了的反而是SQL Server,從dump出來的索引頁我們可以看到SQL Server的Btree索引是存儲null值的,即便全部都是空也會存儲空值+主鍵書簽。而且以上涉及的SQL全部會使用到聯合索引,這點不但方便使用而且也很容易想通。

更多更詳細的測試有待繼續補充。

最后:Oracle數據庫列能添加非空約束的一定要添加,MySQL、SQLServer中可能沒這么嚴格。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM