很多文章都提到使用IN,OR會(huì)破壞索引,造成全表掃描,但實(shí)際測試卻不是這樣。
SELECT c FROM t WHERE c = 1SELECT c FROM t WHERE c in (1)
或者
SELECT c FROM t WHERE c = 1 OR c = 2SELECT c FROM t WHERE c in (1,2)
以上SQL文,第一組(=,IN),第二組(=,OR,IN),每一組的兩個(gè)SQL文都使用相同的執(zhí)行計(jì)劃,執(zhí)行計(jì)劃中也可以看到使用了相同的索引,磁盤活動(dòng)信息中的邏輯讀次數(shù)也相同。
測試中需要的設(shè)定:
SET STATISTICS IO ON 使SQLSERVER顯示Transact-SQL語句生成的磁盤活動(dòng)量信息。
SET STATISTICS TIME ON 顯示分析,編譯,執(zhí)行語句所需要的毫秒數(shù)
每次執(zhí)行查詢前的處理:
CHECKPOINT 強(qiáng)制將當(dāng)前數(shù)據(jù)庫的全部臟頁寫入磁盤,然后清除緩沖區(qū)
DBCC DROPCLEANBUFFERS 從緩沖池中刪除所有CleanBuffers
測試:
SQLServer 2008 R2
SQLServer 2014
1.新建數(shù)據(jù)庫表:
CREATE TABLE [dbo].[TestTable]( [ID] [bigint] IDENTITY(1,1) NOT NULL, [Birthday] [varchar](10) NOT NULL,CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED ( [ID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]
2.向Birthday中插入大量數(shù)據(jù)
3.建立Birthday列的非聚集索引
4.查詢測試
CHECKPOINT DBCC DROPCLEANBUFFERSSELECT birthday FROM [dbo].[TestTable] WHERE Birthday IN ('19901111')
表 'TestTable'。掃描計(jì)數(shù) 1,邏輯讀取 8 次,物理讀取 2 次,預(yù)讀 5 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預(yù)讀 0 次。
CHECKPOINT
DBCC DROPCLEANBUFFERS
SELECT Birthday FROM [dbo].[TestTable] WHERE Birthday IN ('19901111')
表 'TestTable'。掃描計(jì)數(shù) 1,邏輯讀取 8 次,物理讀取 2 次,預(yù)讀 5 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預(yù)讀 0 次。
下面的語句執(zhí)行后,查詢計(jì)劃以及讀取次數(shù)也都是一樣的。
CHECKPOINT DBCC DROPCLEANBUFFERSSELECT Birthday FROM [dbo].[TestTable] WHERE Birthday = '19901111' OR Birthday = '19901212'
表 'TestTable'。掃描計(jì)數(shù) 2,邏輯讀取 16 次,物理讀取 2 次,預(yù)讀 10 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預(yù)讀 0 次。
CHECKPOINT DBCC DROPCLEANBUFFERSSELECT birthday FROM [dbo].[TestTable] WHERE Birthday IN ('19901111','19901212')
表 'TestTable'。掃描計(jì)數(shù) 2,邏輯讀取 16 次,物理讀取 2 次,預(yù)讀 10 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預(yù)讀 0 次。
執(zhí)行計(jì)劃截圖這里就不上傳了,有興趣的話,大家可以自行驗(yàn)證。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注