sql中索引不会被用到的几种情况

本文列举了Oracle数据库中导致索引失效的多种情况,包括查询谓词未充分利用索引、索引列上存在函数运算、隐式类型转换、统计信息不准确等,探讨了如何优化SQL语句以提高查询效率。
1、查询谓词没有使用索引的主要边界,换句话说就是select *,可能会导致不走索引。
比如,你查询的是SELECT * FROM T WHERE Y=XXX;假如你的T表上有一个包含Y值的组合索引,但是优化器会认为需要一行行的扫描会更有效,这个时候,优化器可能会选择TABLE ACCESS FULL,但是如果换成了SELECT Y FROM T WHERE Y = XXX,优化器会直接去索引中找到Y的值,因为从B树中就可以找到相应的值。
 
2、单键值的b树索引列上存在null值,导致COUNT(*)不能走索引。
如果在B树索引中有一个空值,那么查询诸如SELECT COUNT(*) FROM T 的时候,因为HASHSET中不能存储空值的,所以优化器不会走索引,有两种方式可以让索引有效,一种是SELECT COUNT(*) FROM T WHERE XXX IS NOT NULL或者把这个列的属性改为not null (不能为空)。
 
3、索引列上有函数运算,导致不走索引
如果在T表上有一个索引Y,但是你的查询语句是这样子SELECT * FROM T WHERE FUN(Y) = XXX。这个时候索引也不会被用到,因为你要查询的列中所有的行都需要被计算一遍,因此,如果要让这种sql语句的效率提高的话,在这个表上建立一个基于函数的索引,比如CREATE INDEX IDX FUNT ON T(FUN(Y));这种方式,等于Oracle会建立一个存储所有函数计算结果的值,再进行查询的时候就不需要进行计算了,因为很多函数存在不同返回值,因此必须标明这个函数是有固定返回值的。
 
4、隐式转换导致不走索引。
索引不适用于隐式转换的情况,比如你的SELECT * FROM T WHERE Y = 5 在Y上面有一个索引,但是Y列是VARCHAR2的,那么Oracle会将上面的5进行一个隐式的转换,SELECT * FROM T WHERE TO_NUMBER(Y) = 5,这个时候也是有可能用不到索引的。
 
5、表的数据库小或者需要选择大部分数据,不走索引
在Oracle的初始化参数中,有一个参数是一次读取的数据块的数目,比如你的表只有几个数据块大小,而且可以被Oracle一次性抓取,那么就没有使用索引的必要了,因为抓取索引还需要去根据rowid从数据块中获取相应的元素值,因此在表特别小的情况下,索引没有用到是情理当中的事情。
6、cbo优化器下统计信息不准确,导致不走索引
很长时间没有做表分析,或者重新收集表状态信息了,在数据字典中,表的统计信息是不准确的,这个情况下,可能会使用错误的索引,这个效率可能也是比较低的。
7、!=或者<>(不等于),可能导致不走索引,也可能走 INDEX FAST FULL SCAN
例如select id  from test where id<>100
8、表字段的属性导致不走索引,字符型的索引列会导致优化器认为需要扫描索引大部分数据且聚簇因子很大,最终导致弃用索引扫描而改用全表扫描方式
由于字符型和数值型的在insert的时候排序不同,字符类型导致了聚簇因子很大,原因是插入顺序与排序顺序不同。详细点说,就是按照数字类型插入(1..3200000),按字符类型('1'...'32000000')t排序,在对字符类型使用大于运算符时,会导致优化器认为需要扫描索引大部分数据且聚簇因子很大,最终导致弃用索引扫描而改用全表扫描方式。
下面展示测试结果,
两个表的数据类型相似(只是ID字段类型不同),各插入了320万数据,ID字段范围为1~3200000。
模拟场景
相关代码如下:
对于普通的采用数值类型的字段,范围查询就是正常的索引范围扫描,执行效率很高。
对于文本类型字段的表,范围查询就是对应的全表扫描,效率较低是显而易见的。
解决方法
将SQL语句由开放区间扫描(>=),修改为封闭区间(between xxx and max_value)。使得数据在索引局部顺序是“对的”。如果采用这种方式仍然不走索引扫描,还可以进一步细化分段或者采用“逐条提取+批绑定”的方法。
 
9.建立组合索引,但查询谓词并未使用组合索引的第一列,此处有一个INDEX SKIP SCAN概念,
10、like '%liu' 百分号在前
11,not in ,not exist
可以尝试把not in 或者 not exsts改成左连接的方式(前提是有子查询,并且子查询有where条件)。
例如:
SELECT
    /*+ INDEX(I CIRCLEICONMAST_IX1)*/
    I.ICONNO,
    I.CIRCLEID,
    I.FILEPATH,
    I.REGDT,
    I.FILEPATH || '/' || I.FILENAME IMGNAME,
    I.FILEPATH || '/' || 'th_160_' || I.FILENAME SMALLIMGNAME,
    I.MEMBERID,
    I.ADMCHK STATUS,
    I.ADMCHK ORIGINALSTATUS,
    ROWNUM RN
     FROM CIRCLEICONMAST I
    WHERE I.REGDT BETWEEN TO_DATE('20120619', 'YYYYMMDD') - 10000 AND
      TO_DATE('20120621', 'YYYYMMDD')
      AND NOT EXISTS (
       SELECT C.VALIDFLG
         FROM CIRCLEMAST C
        WHERE C.VALIDFLG IN ('N', 'F')
        AND I.CIRCLEID = C.CIRCLEID)      
      AND I.ADMCHK = 'N'
 
改成左连接:
SELECT
/*+ INDEX(I CIRCLEICONMAST_IX1)*/
I.ICONNO,
I.CIRCLEID,
I.FILEPATH,
I.REGDT,
I.FILEPATH || '/' || I.FILENAME IMGNAME,
I.FILEPATH || '/' || 'th_160_' || I.FILENAME SMALLIMGNAME,
I.MEMBERID,
I.ADMCHK STATUS,
I.ADMCHK ORIGINALSTATUS,
ROWNUM RN
  FROM CIRCLEICONMAST I, CIRCLEMAST C
WHERE I.REGDT BETWEEN TO_DATE('20110620', 'YYYYMMDD') AND
       TO_DATE('20120621', 'YYYYMMDD') + 1
   AND C.VALIDFLG NOT IN ('N', 'F')
   AND I.CIRCLEID = C.CIRCLEID
      
   AND I.ADMCHK = 'N'
总结:oracle中有很多情况会导致index失效,并且走全表扫描的代价是相当大的,所以在写sql的时候一定要注意这个会使索引失效的情况,养成良好的习惯。
<think>好的,用户想知道如何通过SQL Server的查询执行计划来分析是否使用了索引。首先,我需要回忆一下相关知识,并结合之前提供的引用内容来组织答案。用户的问题集中在执行计划的分析,特别是索引的使用情况。根据引用内容,比如引用[2]和引用[4],提到了执行计划中的索引查找和键查找,以及如何查看索引使用情况。我需要先解释如何获取执行计划,然后如何解读其中的关键部分。 首先,获取执行计划的方法可能有几种,比如在SSMS中直接使用“包括实际执行计划”的选项,或者使用SET STATISTICSXMLON。这些方法在引用[3]中也有提到,关于保存不同版本执行计划进行比较。接下来,分析执行计划时,需要关注哪些操作符。索引扫描(IndexScan)和索引查找(Index Seek)的区别很重要。索引扫描可能意味着没有有效利用索引,而索引查找则说明使用了索引。引用[2]中提到非聚集索引的查找和键值查找,这可能涉及到RID或键查找,说明需要回表获取数据,这时候可能影响性能。然后,如何判断是否使用索引?用户可能需要查看执行计划中的操作符,比如有没有出现Index Seek,或者是否有扫描操作。此外,引用[4]中的查询可以用来查看索引使用情况,比如sys.dm_db_index_usage_stats,这可能也是一个补充方法。另外,用户可能需要优化建议,比如缺失索引提示。执行计划有时会提示缺失的索引,这需要提到。引用[3]中的优化最佳实践部分可以支持这一点。还要注意可能的陷阱,比如书签查找(Key Lookup)虽然使用了索引,但可能效率不高,需要结合覆盖索引来优化。引用[2]中的例子正好说明了这种情况,非聚集索引缺少某些列导致需要回表查询,这时候可能需要调整索引。最后,确保步骤清晰,从获取执行计划到分析关键点,再到优化建议,逐步引导用户完成分析。同时,生成的相关问题需要围绕索引使用和执行计划分析展开,比如如何优化索引、解决键查找问题等。</think>### 如何通过SQL Server查询执行计划分析索引使用情况? #### 一、获取执行计划的3种方法 1. **图形化执行计划** 在SSMS中执行查询时,点击「包括实际执行计划」按钮(快捷键:$Ctrl+M$),结果页会生成可视化执行流程图。图标中绿色箭头表示索引查找(Index Seek),红色箭头表示索引扫描(Index Scan)[^2][^3]。 2. **文本执行计划** ```sql SET SHOWPLAN_TEXT ON; GO -- 执行目标查询 GO SET SHOWPLAN_TEXT OFF; ``` 3. **XML格式执行计划** ```sql SET STATISTICS XML ON; -- 执行目标查询 SET STATISTICS XML OFF; ``` #### 二、分析执行计划的4个关键点 1. **索引查找(Index Seek)** - 符号:绿色箭头图标 - 含义:通过B+树直接定位数据行,效率高 - 示例:`NonClustered Index Seek (SEEK:([firstname]=N'John'))`[^2] 2. **索引扫描(Index Scan)** - 符号:红色箭头图标 - 含义:遍历整个索引叶子节点 - 常见场景:无适合的WHERE条件、统计信息过时 3. **键查找(Key Lookup)** - 符号:嵌套在索引查找后的黄色箭头 - 问题:通过非聚集索引找到主键后,需回聚集索引取其他列 - 优化方案:创建覆盖索引(INCLUDE缺失列)[^2] 4. **缺失索引提示** ```xml <MissingIndexes> <MissingIndexGroup Impact="94.413"> <MissingIndex Database="[DB]" Schema="[dbo]" Table="[Employees]"> <ColumnGroup Usage="EQUALITY"> <Column Name="[DepartmentID]"/> </ColumnGroup> </MissingIndex> </MissingIndexGroup> </MissingIndexes> ``` #### 三、验证索引使用的2种补充方法 1. **索引使用统计查询** ```sql SELECT i.name AS IndexName, user_seeks + user_scans + user_lookups AS TotalReads FROM sys.dm_db_index_usage_stats us JOIN sys.indexes i ON us.object_id = i.object_id AND us.index_id = i.index_id WHERE us.object_id = OBJECT_ID('YourTable'); ``` 2. **Query Store分析** ```sql ALTER DATABASE YourDB SET QUERY_STORE = ON; SELECT qsp.query_id, qsqt.query_sql_text, qsp.plan_id, qsp.is_forced_plan FROM sys.query_store_plan qsp JOIN sys.query_store_query qsq ON qsp.query_id = qsq.query_id JOIN sys.query_store_query_text qsqt ON qsq.query_text_id = qsqt.query_text_id; ``` #### 四、典型问题案例分析 **场景**:某查询在`WHERE City='London'`时出现`Clustered Index Scan` **诊断步骤**: 1. 检查是否存在`City`字段的索引:`EXEC sp_helpindex 'Customers';` 2. 确认索引包含必要字段:若需返回`Phone`字段,建议创建`CREATE INDEX IX_City ON Customers(City) INCLUDE (Phone)` 3. 更新统计信息:`UPDATE STATISTICS Customers;` #### 五、优化建议 1. 对高频率查询字段建立复合索引 2. 定期重建碎片率超过30%的索引 3. 避免在WHERE条件中对索引列进行函数运算
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值