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

本文详细解释了SQL中聚集索引和非聚集索引的工作原理,包括如何根据查询条件选择合适的索引进行数据检索,以及不同场景下索引的选择策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

走索引指的是:SQL语句的执行计划用到了1、聚集索引查找  2、索引查找  ,并且查询语句中需要有where子句

根据where子句的过滤条件,去聚集索引或非聚集索引那里查找记录

一张表只有一列的情况:

聚集索引

 
 USE [tempdb]
 GO
 CREATE TABLE t1 ( id INT )
 GO
 CREATE CLUSTERED INDEX CIX_T1 ON [dbo].[t1](ID ASC)
 GO


 DECLARE @I INT
 SET @I = 1
 WHILE @I < 1000 
     BEGIN
         INSERT  INTO [dbo].[t1] ( [id] )
                 SELECT  @I
         SET @I = @I + 1
     END

 SELECT * FROM [dbo].[t1] WHERE [id]=20
View Code

 

非聚集索引

 
 USE [tempdb]
 GO
 
 CREATE TABLE t2 ( id INT )
 GO
 CREATE NONCLUSTERED INDEX IX_T2 ON [dbo].[t2](ID ASC)
 GO


 DECLARE @I INT
 SET @I = 1
 WHILE @I < 1000 
     BEGIN
         INSERT  INTO [dbo].[t2] ( [id] )
                 SELECT  @I
         SET @I = @I + 1
     END

 SELECT * FROM [dbo].[t2] WHERE [id]=20
View Code

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


一张表有多列的情况

分三种情况:

1、只有聚集索引

2、只有非聚集索引

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


只有聚集索引

 --只有聚集索引
 USE [tempdb]
 GO
 CREATE TABLE Department  
 (
   DepartmentID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
   Name NVARCHAR(200) NOT NULL ,
   GroupName NVARCHAR(200) NOT NULL ,
   Company NVARCHAR(300) ,
   ModifiedDate DATETIME NOT NULL DEFAULT ( GETDATE() ) 

 )

 
 DECLARE @i INT
 SET @i=1
 WHILE @i < 100000 
     BEGIN
         INSERT  INTO Department ( name, [Company], groupname )
         VALUES  ( '销售部'+CAST(@i AS VARCHAR(200)), '中国你好有限公司XX分公司', '销售组' )
         SET @i = @i + 1
     END


 SELECT * FROM [dbo].[Department] WHERE [DepartmentID]=2
View Code

小结:

只有聚集索引的表:如果where后面不包括创建聚集索引的时候的第一个字段,就会使用聚集索引扫描

下面SQL语句会使用聚集索引查找,因为包括了创建聚集索引的时候的第一个字段

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

只有非聚集索引

 
 --只有非聚集索引
 USE [tempdb]
 GO

 CREATE TABLE Department  
 (
   DepartmentID INT IDENTITY(1, 1) NOT NULL ,
   Name NVARCHAR(200) NOT NULL ,
   GroupName NVARCHAR(200) NOT NULL ,
   Company NVARCHAR(300) ,
   ModifiedDate DATETIME NOT NULL DEFAULT ( GETDATE() ) 
 
 )
 
 CREATE NONCLUSTERED INDEX IX_Department ON Department(DepartmentID ASC)

 DECLARE @i INT
 SET @i=1
 WHILE @i < 100000 
     BEGIN
         INSERT  INTO Department ( name, [Company], groupname )
         VALUES  ( '销售部'+CAST(@i AS VARCHAR(200)), '中国你好有限公司XX分公司', '销售组' )
         SET @i = @i + 1
     END
 
SELECT * FROM [dbo].[Department] WHERE [Company]='销售部12' AND [DepartmentID]=12
View Code

 

小结:

只有非聚集索引的表:如果where后面不包括创建非聚集索引的时候的第一个字段,就会使用表扫描或者索引扫描

下面SQL语句会使用非聚集索引查找,因为包括了创建非聚集索引的时候的第一个字段

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

 


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

复制代码
 --有聚集索引和非聚集索引
 USE [tempdb]
 GO
 
 CREATE TABLE Department  
(
  DepartmentID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
  Name NVARCHAR(200) NOT NULL ,
  GroupName NVARCHAR(200) NOT NULL ,
  Company NVARCHAR(300) ,
  ModifiedDate DATETIME NOT NULL DEFAULT ( GETDATE() ) 
 
)
 
CREATE NONCLUSTERED INDEX IX_Department ON Department(Company ASC)
 

 DECLARE @i INT
 SET @i=1
 WHILE @i < 100000 
     BEGIN
         INSERT  INTO Department ( name, [Company], groupname )
         VALUES  ( '销售部'+CAST(@i AS VARCHAR(200)), '中国你好有限公司XX分公司', '销售组' )
         SET @i = @i + 1
     END
View Code

小结:

有聚集索引和非聚集索引的表:如果where后面包括创建聚集索引的时候的第一个字段,就会使用聚集索引查找

如果where后面包括创建非聚集索引的时候的第一个字段但不包括创建聚集索引的时候的第一个字段,就会使用索引查找

如果where后面不包括创建非聚集索引的时候的第一个字段和不包括创建聚集索引的时候的第一个字段,就会使用聚集索引扫描

1 SELECT * FROM [dbo].[Department] WHERE [GroupName]='销售组'


总结

其实走不走索引,关键取决于where后面包括还是不包括

创建聚集索引的时候的第一个字段

创建非聚集索引的时候的第一个字段

跟select *没有关系的,select * 最大的影响就是额外的IO开销

像“键查找” ,“RID查找”这些运算符就是额外的开销

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

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

 

<think>嗯,用户问的是“Select * 一定索引吗”,我需要先理解这个问题的核心。用户可能对索引使用条件和范围太清楚,想知道是否所有情况下使用SELECT *都会导致索引失效或者无法使用索引。 首先,我应该回顾一下数据库索引的基本原理。索引的作用是帮助快速定位数据,通常是对某些列建立的。SELECT * 是选择所有列,而索引可能只包含部分列的数据。所以当查询需要返回索引中的列时,数据库必须回表查询原始数据页,这时候即使使用索引,也可能需要额外的步骤。 接下来要考虑同的情况。比如,如果表中有一个覆盖索引(Covering Index),也就是索引包含了查询需要的所有列,那么SELECT * 是否使用这个索引呢?这里可能有个误区,覆盖索引通常是指索引包含了查询中涉及的所有列,但如果是SELECT *,而索引没有包含所有列,那么覆盖索引的条件就满足。反之,如果索引真的包含了所有列,那么可能使用索引,但这种情况比较少见,因为索引的大小会很大,一般推荐这样做。 然后,考虑全表扫描的情况。当没有合适的索引,或者索引的选择性高时,数据库优化器可能会选择全表扫描,这时候无论是否使用SELECT *,都索引。但问题在于SELECT *是否一定会导致这种情况,显然是绝对的,需要具体情况分析。 另外,还要想到聚簇索引的情况,比如InnoDB的主键索引。当查询通过主键查找时,即使使用SELECT *,也会使用主键索引,因为数据就存储在索引的叶子节点中。这时候SELECT *是可以索引的。 可能还需要提到执行计划的分析,比如使用EXPLAIN语句来查看实际是否使用索引同数据库系统可能有同的优化策略,比如MySQL、PostgreSQL等处理方式可能略有同。 还要注意是否存在查询条件,即WHERE子句。如果WHERE条件中的列有索引,即使SELECT *,优化器可能会使用索引来快速定位行,然后再回表获取其他列的数据。这时候索引是被使用的,只是多了一个回表的步骤,所以能说SELECT *一定索引。 总结的话,需要分情况讨论:是否存在覆盖索引、查询条件是否索引、聚簇索引的情况等。因此,SELECT *一定会导致索引,而是取决于具体的查询结构、表结构和索引设计。 最后,应该提醒用户,虽然SELECT *在某些情况下可以使用索引,但为了优化查询效率和减少I/O,最好明确指定需要的列,尤其是在有覆盖索引的情况下,这样可以避免回表,提升性能。</think>SELECT * 是否索引取决于多个因素,能简单认为“一定索引”。以下是关键点分析: --- ### **一、索引覆盖决定因素** 1. **覆盖索引场景** -索引包含所有查询字段(包括SELECT *),则可能触发**索引覆盖**(Covering Index),此时直接通过索引返回数据,无需回表。 - 例:表 `user(id PK, name, age)`,索引 `idx_name_age(name, age)`,执行 `SELECT name, age` 时可能索引;但 `SELECT *` 需要额外读取主键索引中的其他列。 2. **非覆盖索引场景** -索引未覆盖所有列,即使WHERE条件命中索引,执行 `SELECT *` 仍需**回表查询**(通过主键或ROWID访问数据页),此时索引仅用于定位数据行。 --- ### **二、聚簇索引的特殊性** - **InnoDB主键索引**:数据直接存储在聚簇索引的叶子节点中。 - 查询主键范围时(如 `WHERE id > 100`),即使使用 `SELECT *`,仍会聚簇索引--- ### **三、执行计划的影响因素** 1. **优化器成本估算** - 优化器会对比全表扫描与索引扫描的成本。 -索引过滤后需回表的数据量过大(如90%行),可能直接选择全表扫描。 2. **查询条件匹配度** - WHERE条件命中索引时,`SELECT *` 可能先索引定位行,再回表获取其他列。 - 例:表 `orders(order_id PK, user_id, amount)`,索引 `idx_user_id(user_id)`,查询 `SELECT * FROM orders WHERE user_id=123` 会使用 `idx_user_id` 索引--- ### **四、示例验证(MySQL** ```sql -- 创建测试表 CREATE TABLE test ( id INT PRIMARY KEY, a INT, b INT, INDEX idx_a (a) ); -- 执行查询 EXPLAIN SELECT * FROM test WHERE a = 10; ``` - **执行计划结果**- 若 `type=ref` 且 `key=idx_a`,说明使用索引,但 `Extra` 列显示 `Using index condition`,表示需要回表。 - 若改为 `SELECT a`,则 `Extra` 显示 `Using index`,表示无需回表。 --- ### **五、最佳实践** 1. **避免滥用SELECT *** - 明确指定所需列,减少数据传输和I/O开销。 2. **合理设计覆盖索引** - 对高频查询字段建立覆盖索引,避免回表。 3. **监控执行计划** - 使用 `EXPLAIN` 分析实际索引使用情况。 --- ### **结论** - **SELECT * 可能索引**:当索引覆盖所有列,或WHERE条件命中索引且优化器认为索引扫描更高效时。 - **SELECT * 可能索引**:当需要大量回表或全表扫描成本更低时。 - **核心原则**索引是否使用取决于**查询条件****索引设计****优化器决策**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值