Select * 一定不走索引是否正確?


Select * 一定不走索引是否正確?

走索引指的是:SQL語句的執行計划用到了1、聚集索引查找  2、索引查找  ,並且查詢語句中需要有where子句

根據where子句的過濾條件,去聚集索引或非聚集索引那里查找記錄

一張表只有一列的情況:

聚集索引

 1 USE [tempdb]
 2 GO
 3 CREATE TABLE t1 ( id INT )
 4 GO
 5 CREATE CLUSTERED INDEX CIX_T1 ON [dbo].[t1](ID ASC)
 6 GO
 7 
 8 
 9 DECLARE @I INT
10 SET @I = 1
11 WHILE @I < 1000 
12     BEGIN
13         INSERT  INTO [dbo].[t1] ( [id] )
14                 SELECT  @I
15         SET @I = @I + 1
16     END
17 
18 SELECT * FROM [dbo].[t1] WHERE [id]=20
View Code

 

非聚集索引

 1 USE [tempdb]
 2 GO
 3 
 4 CREATE TABLE t2 ( id INT )
 5 GO
 6 CREATE NONCLUSTERED INDEX IX_T2 ON [dbo].[t2](ID ASC)
 7 GO
 8 
 9 
10 DECLARE @I INT
11 SET @I = 1
12 WHILE @I < 1000 
13     BEGIN
14         INSERT  INTO [dbo].[t2] ( [id] )
15                 SELECT  @I
16         SET @I = @I + 1
17     END
18 
19 SELECT * FROM [dbo].[t2] WHERE [id]=20
View Code

只有一列,肯定會走索引的


一張表有多列的情況

分三種情況:

1、只有聚集索引

2、只有非聚集索引

3、有聚集索引和非聚集索引


只有聚集索引

 1 --只有聚集索引
 2 USE [tempdb]
 3 GO
 4 CREATE TABLE Department  
 5 (
 6   DepartmentID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
 7   Name NVARCHAR(200) NOT NULL ,
 8   GroupName NVARCHAR(200) NOT NULL ,
 9   Company NVARCHAR(300) ,
10   ModifiedDate DATETIME NOT NULL DEFAULT ( GETDATE() ) 
11 
12 )
13 
14 
15 DECLARE @i INT
16 SET @i=1
17 WHILE @i < 100000 
18     BEGIN
19         INSERT  INTO Department ( name, [Company], groupname )
20         VALUES  ( '銷售部'+CAST(@i AS VARCHAR(200)), '中國你好有限公司XX分公司', '銷售組' )
21         SET @i = @i + 1
22     END
23 
24 
25 SELECT * FROM [dbo].[Department] WHERE [DepartmentID]=2
View Code

小結:

只有聚集索引的表:如果where后面不包括創建聚集索引的時候的第一個字段,就會使用聚集索引掃描

下面SQL語句會使用聚集索引查找,因為包括了創建聚集索引的時候的第一個字段

1 SELECT * FROM [dbo].[Department] WHERE [Company]='銷售部12' AND [DepartmentID]=12

只有非聚集索引

 1 --只有非聚集索引
 2 USE [tempdb]
 3 GO
 4 
 5 CREATE TABLE Department  
 6 (
 7   DepartmentID INT IDENTITY(1, 1) NOT NULL ,
 8   Name NVARCHAR(200) NOT NULL ,
 9   GroupName NVARCHAR(200) NOT NULL ,
10   Company NVARCHAR(300) ,
11   ModifiedDate DATETIME NOT NULL DEFAULT ( GETDATE() ) 
12 
13 )
14 
15 CREATE NONCLUSTERED INDEX IX_Department ON Department(DepartmentID ASC)
16 
17 
18 DECLARE @i INT
19 SET @i=1
20 WHILE @i < 100000 
21     BEGIN
22         INSERT  INTO Department ( name, [Company], groupname )
23         VALUES  ( '銷售部'+CAST(@i AS VARCHAR(200)), '中國你好有限公司XX分公司', '銷售組' )
24         SET @i = @i + 1
25     END
26 
27 
28 SELECT * FROM [dbo].[Department] WHERE [Company]='銷售部12' AND [DepartmentID]=12
View Code

 

小結:

只有非聚集索引的表:如果where后面不包括創建非聚集索引的時候的第一個字段,就會使用表掃描或者索引掃描

下面SQL語句會使用非聚集索引查找,因為包括了創建非聚集索引的時候的第一個字段

1 SELECT * FROM [dbo].[Department] WHERE [Company]='銷售部12' AND [DepartmentID]=12

 


有聚集索引也有非聚集索引

 1 --有聚集索引和非聚集索引
 2 USE [tempdb]
 3 GO
 4 
 5 CREATE TABLE Department  
 6 (
 7   DepartmentID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
 8   Name NVARCHAR(200) NOT NULL ,
 9   GroupName NVARCHAR(200) NOT NULL ,
10   Company NVARCHAR(300) ,
11   ModifiedDate DATETIME NOT NULL DEFAULT ( GETDATE() ) 
12 
13 )
14 
15 CREATE NONCLUSTERED INDEX IX_Department ON Department(Company ASC)
16 
17 
18 DECLARE @i INT
19 SET @i=1
20 WHILE @i < 100000 
21     BEGIN
22         INSERT  INTO Department ( name, [Company], groupname )
23         VALUES  ( '銷售部'+CAST(@i AS VARCHAR(200)), '中國你好有限公司XX分公司', '銷售組' )
24         SET @i = @i + 1
25     END
View Code

小結:

有聚集索引和非聚集索引的表:如果where后面包括創建聚集索引的時候的第一個字段,就會使用聚集索引查找

如果where后面包括創建非聚集索引的時候的第一個字段但不包括創建聚集索引的時候的第一個字段,就會使用索引查找

如果where后面不包括創建非聚集索引的時候的第一個字段和不包括創建聚集索引的時候的第一個字段,就會使用聚集索引掃描

1 SELECT * FROM [dbo].[Department] WHERE [GroupName]='銷售組'


總結

其實走不走索引,關鍵取決於where后面包括還是不包括

創建聚集索引的時候的第一個字段

創建非聚集索引的時候的第一個字段

跟select *沒有關系的,select * 最大的影響就是額外的IO開銷

像“鍵查找” ,“RID查找”這些運算符就是額外的開銷

鍵查找:到聚集索引里找其他字段的值

RID查找:到堆表里找其他字段的值

 

而在宋大俠的文章里:有關T-SQL的10個好習慣

他說到:

 造成額外的書簽查找或是由查找變為掃描

由查找變為掃描,查找還是掃描決定於我剛才所說的話:

其實走不走索引,關鍵取決於where后面包括還是不包括

創建聚集索引的時候的第一個字段

創建非聚集索引的時候的第一個字段

如果大家不是很明白,可以看一下我所寫的文章,我在文章里對聚集索引跟非聚集索引的研究還是比較透徹的

SQLSERVER聚集索引與非聚集索引的再次研究(上)

SQLSERVER聚集索引與非聚集索引的再次研究(下)

 

當然,您也不能把整個表的字段全部放到索引里,以消除額外IO開銷,要針對實際情況,

該把要加入索引的字段就加入索引,不該把不用加入索引的字段不要加入索引

那么您剛才說:走索引不是where后面包括還是不包括創建索引的第一個字段嗎???既然這樣創建索引的時候只包括一個字段就好了

大家可以看一下SQLSERVER聚集索引與非聚集索引的再次研究(下),其實非聚集索引掃描也是很有用的

而聚集索引就只包括一個字段就行了,非聚集索引可以包括多個字段,詳細還是看一下下面兩篇文章吧o(∩_∩)o

SQLSERVER聚集索引與非聚集索引的再次研究(上)

SQLSERVER聚集索引與非聚集索引的再次研究(下)

 

 

不過大家還是不要用select * 比較好,老老實實寫上字段名

有一些偷懶的人總是會有他的理由:

如果表結構改變我就不用修改代碼 ,方便省事,一個select *搞定,項目這麽緊張還寫上字段干嘛???

如果您是上面那種人,那好吧,當我沒說過好了o(∩_∩)o

如有不對的地方,歡迎大家拍磚哦o(∩_∩)o


免責聲明!

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



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