记一次T-SQL查询优化 索引的重要性

简介: 原文:记一次T-SQL查询优化 索引的重要性概述 在一次调优一个项目组件的性能问题时,发现SQL的设计真的是非常的重要,所以写一篇博文来记录总结一下。 环境介绍 这个项目组件是一个Window服务,内部在使用轮循机会在处理一个事件表中的事件,将其转换在对应的任务。
原文: 记一次T-SQL查询优化 索引的重要性

概述

在一次调优一个项目组件的性能问题时,发现SQL的设计真的是非常的重要,所以写一篇博文来记录总结一下。

环境介绍

这个项目组件是一个Window服务,内部在使用轮循机会在处理一个事件表中的事件,将其转换在对应的任务。性能问题在于,统计下来,这个服务一秒的时间内只能处理完成12条左右。这个性能是非常的差。

我使用的SQL版本是SQL 2012,机器是CPU I7-2670,内存16G,SSD硬盘。

在这个数据库中有一个表的数据量大概30万条数据,并不是很多, 事先没有建立任何索引,只有一个主键的索引。

 那么在这其中有一条非常简单的查询语句:

SELECT TOP 1 * 
FROM SMS_SHORTNO_ASSIGN 
WHERE 
	APP_CODE = 'SMSNotice'
	AND IS_DYNAMIC_ASSIGN = 'N'
	AND SMS_TYPE_CODE = 'Mas'

有数据和无数据的性能对比

 在上面的查询中,IS_DYNAMIC_ASSIGN = 'N'是查询不到任何数据的,IS_DYNAMIC_ASSIGN = 'Y'是有数据的,对比一下,在没有任何数据的情况下,查询是非常的慢,但是有数据的情况下,就不同了。

首先来看一下这个SQL的查询计划是什么样子:

下面是更清晰的执行查询计划:

 可以看到,在没有索引的情况下,会执行表扫描。

 来看一下各自的执行时间:

可以查询到数据:

不能查询到数据:

可以看到,在没有查询到数据的情况下,总共需要耗时89ms. 不要觉得89ms才只有0.1s都不到,但是想一想之前上面说的1S钟才处理12条记录,就可以想像到和这个89ms有相当大的关系,如果只执行这一条SQL,那么1S钟也只能执行12条左右。

在这种情况下,我们来优化一下这条SQL语句。首先这句SQL本身已经是最简单的,不能再简化,那么只有在索引上下功夫。

聚集索引和非聚集索引

两者之间有什么区别呢?大家可以参考一篇博客圆另一博主的博文 聚集索引和非聚集索引(整理)

首先我们按照我们一般没有深入研究过索引童鞋们的思路,就是把WHERE后面条件的字段加起来建一个索引。

根据WHERE 条件字段创建非聚集索引

 

创建后好,我们来看看上面的语句的查询计划:

咦,为什么还是使用了表扫描呢,而不用使用索引呢?  

在这里贴上一篇博文 Select * 一定不走索引是否正确? 这篇博文分析了SELECT * 和各种索引的关系,但是这个博文里面分析的和我得出的结论不一样,我也在作者的评论留言了,同时我找到别一篇博文 SELECT * 的真相: 索引覆盖(index coverage) 来解释我现在的现象。因为我不怎么研究SQL,所以我不清楚到底是什么原因,望有知者,可以告知一下。关于索引覆盖也可以参考这篇博文 SQL Server 查询性能优化——覆盖索引(二)

那么我现在将SELECT * 改成 SELECT 字段后,索引才真正的应用了。

可以看到如果SELECT中的字段包含在索引中,将可以利用到索引。

但是这样的话,改变了我原来程序的用意,这是不能接受的。那有什么别的办法可以解决吗?这个时候我想到了聚集索引。

创建聚集索引

默认情况下,在使用表设计器的创建表的时候,会默认创建一个主键的聚集索引。根据主键创建聚集索引,并不一定是最优的选择。关于聚集索引 可以参考下 索引优化(2)聚集索引 。我观察了一下我的表结构,我根据可能使用的列频率最高的两个字段上建立了聚集索引,这两个字段包含在上述语句的WHERE语句中。这两个字段并不是主键。

创建好后,我们再来看一下查询计划和查询的时间:

查询时间:

可以看到,查询速度已经0ms了,非常的快速了。到这里面,其实问题关于这一条SQL优化应该是已经结束了。

聚集索引很重要并且一个表只能建一条聚集索引,不能根据某一条SQL的WHERE来建立,而是要考虑到各种不同的WHERE条件才确定这样建立聚集索引是不是最优的,我根据这两个字段建立好聚集索引后,我使用别的WHERE来查询,速度也是非常的快,所以最后才确认使用这两个字段建聚集索引。

当然我的项目中还是有很多的语句可以优化,以及程序C#代码本身也可以优化,经过我的优化后,处理速度可以达到1秒处理130条左右了。

题外篇

 ===========================题外篇=======================

在学习这个优化过程中,还有一些别的心得和疑问的,也在此记录一下。

根据上面我创建一条聚集索引就解决了问题,并且也建立了非聚集索引,非聚集索引反而没有用上,那么是不是说非聚集索引就没有用呢?并不是这样的,非聚集索引是SQL优化的很大的一部分。

之前上面说道SELECT中只包含索引列的情况下会使用到非聚焦索引。那么下面再说一个例子来说明非聚集索引的用途。

我们们将之前建立的三个字段的非聚集索引删除,使用统计函数来统计一下符合条件的条数:

查询时间:

可以看到耗时还是很久28ms的. 大家不用关注COUNT(*)可以使用COUNT(1)或Count(主键),这个讨论网上也很多,我自己切换三种写法也没有什么本质的不同。

这时,我们将之前删除的非聚集索引加回来,再来查看查询计划和时间:

可以看到查询计划中,这个时候优先使用了非聚集索引,并且统计的速度是要快过使用聚集索引的。 

疑问(求答疑)

在别一个SQL中,也是很简单的SQL,使用了LEFT JOIN后,会导致查询的性能不高,在这种情况下,该如何来优化呢,我使用了not Exists,子查询来各种替换并不能减少这个SQL的查询时间。

业务场景是这样的,SQL还是和之前的一样,SMS_SHORTNO_LOCKED表里面会存入SMS_SHORTNO_ASSIGN表里面的记录,锁定的时候会增加一条,解锁的时候会将这条记录删除,所以在此使用LEFT JOIN来取出一条没有锁定的记录。

下面是它的查询语句和查询计划和响应时间:

这个26ms最主要是在SHORTNO_LOCKED IS NULL这条判断上,如果不是使用IS NULL,而是使用 SHORTNO_LOCKED = 1或=0这种方法来判断的话,查询是非常的快。

那么在此,请问一下大家,相信很多人都使用LEFT JOIN,然后使用IS NULL来判断别一个表没有的数据。但是这样的性能并不是很高,有什么办法可以解决LEFT JOIN的问题,或者可以改成别的写法,我尝试了很多种都没有改善。

所以我想难道以后在设计表的时候,是不是尽量使用 INNER JOIN ,然后根据某一个字段判断特定的值,这样的话,这个字段可以使用索引来优化,像上面就因为IS NULL的问题是没办法使用索引的。

希望有高人指点,谢谢。

目录
相关文章
|
5月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
8月前
|
SQL 存储 关系型数据库
SQL优化策略与实践:组合索引与最左前缀原则详解
本文介绍了SQL优化的多种方式,包括优化查询语句(避免使用SELECT *、减少数据处理量)、使用索引(创建合适索引类型)、查询缓存、优化表结构、使用存储过程和触发器、批量处理以及分析和监控数据库性能。同时,文章详细讲解了组合索引的概念及其最左前缀原则,即MySQL从索引的最左列开始匹配条件,若跳过最左列,则索引失效。通过示例代码,展示了如何在实际场景中应用这些优化策略,以提高数据库查询效率和系统响应速度。
366 10
|
9月前
|
SQL 索引
【YashanDB知识库】字段加上索引后,SQL查询不到结果
【YashanDB知识库】字段加上索引后,SQL查询不到结果
|
SQL 存储 关系型数据库
如何巧用索引优化SQL语句性能?
本文从索引角度探讨了如何优化MySQL中的SQL语句性能。首先介绍了如何通过查看执行时间和执行计划定位慢SQL,并详细解析了EXPLAIN命令的各个字段含义。接着讲解了索引优化的关键点,包括聚簇索引、索引覆盖、联合索引及最左前缀原则等。最后,通过具体示例展示了索引如何提升查询速度,并提供了三层B+树的存储容量计算方法。通过这些技巧,可以帮助开发者有效提升数据库查询效率。
1114 2
|
9月前
|
SQL 数据库 数据安全/隐私保护
SQL查询优化:where子句的高效使用方式
总的来说,如果将 SQL 查询比喻为一个乐团的演奏,WHERE 子句就像是独奏者,它需要各位乐手的协助,才能发挥出最美妙的音乐。计划好你的演奏,挑选对的音符,在最适当的时间开始演奏,那么,你可以更高效地运用 SQL 查询,更好地把握数据的篇章。
214 19
|
9月前
|
SQL 数据库 数据安全/隐私保护
SQL查询优化:where子句的高效使用方式。
总的来说,如果将 SQL 查询比喻为一个乐团的演奏,WHERE 子句就像是独奏者,它需要各位乐手的协助,才能发挥出最美妙的音乐。计划好你的演奏,挑选对的音符,在最适当的时间开始演奏,那么,你可以更高效地运用 SQL 查询,更好地把握数据的篇章。
155 13
|
10月前
|
SQL 关系型数据库 OLAP
云原生数据仓库AnalyticDB PostgreSQL同一个SQL可以实现向量索引、全文索引GIN、普通索引BTREE混合查询,简化业务实现逻辑、提升查询性能
本文档介绍了如何在AnalyticDB for PostgreSQL中创建表、向量索引及混合检索的实现步骤。主要内容包括:创建`articles`表并设置向量存储格式,创建ANN向量索引,为表增加`username`和`time`列,建立BTREE索引和GIN全文检索索引,并展示了查询结果。参考文档提供了详细的SQL语句和配置说明。
356 2
|
存储 SQL 关系型数据库
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
MySQL调优主要分为三个步骤:监控报警、排查慢SQL、MySQL调优。 排查慢SQL:开启慢查询日志 、找出最慢的几条SQL、分析查询计划 。 MySQL调优: 基础优化:缓存优化、硬件优化、参数优化、定期清理垃圾、使用合适的存储引擎、读写分离、分库分表; 表设计优化:数据类型优化、冷热数据分表等。 索引优化:考虑索引失效的11个场景、遵循索引设计原则、连接查询优化、排序优化、深分页查询优化、覆盖索引、索引下推、用普通索引等。 SQL优化。
1718 15
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
|
存储 关系型数据库 MySQL
MySQL高级篇——覆盖索引、前缀索引、索引下推、SQL优化、主键设计
覆盖索引、前缀索引、索引下推、SQL优化、EXISTS 和 IN 的区分、建议COUNT(*)或COUNT(1)、建议SELECT(字段)而不是SELECT(*)、LIMIT 1 对优化的影响、多使用COMMIT、主键设计、自增主键的缺点、淘宝订单号的主键设计、MySQL 8.0改造UUID为有序
MySQL高级篇——覆盖索引、前缀索引、索引下推、SQL优化、主键设计
|
SQL Oracle 关系型数据库
SQL优化-使用联合索引和函数索引
在一次例行巡检中,发现一条使用 `to_char` 函数将日期转换为字符串的 SQL 语句 CPU 利用率很高。为了优化该语句,首先分析了 where 条件中各列的选择性,并创建了不同类型的索引,包括普通索引、函数索引和虚拟列索引。通过对比不同索引的执行计划,最终确定了使用复合索引(包含函数表达式)能够显著降低查询成本,提高执行效率。
237 3