使用正确的筛选参数来提高查询性能

在今天的文章里我想谈下SQL Server里与索引相关的特殊性能问题。

问题描述

假设下列的简单查询,在你的日常SQL Server里,这样的查询你已经看到过几百遍了:

1 -- Results in an Index Scan
2 SELECT * FROM Sales.SalesOrderHeader
3 WHERE YEAR(OrderDate) = 2005 AND MONTH(OrderDate) = 7
4 GO

用那个简单查询,我们请求在特定年份特定月份里的销售信息。并不复杂。遗憾的是这个查询性能很差——即使在OrderDate列使用了非聚集索引。当你查看执行计划时,你会看到查询优化器选择了在OrderDate列上的非聚集索引,但遗憾的是SQL Server进行的索引的全扫描,而不是高效的查找操作。

这真不是SQL Server的局限性,而是关系数据库的工作和思考方式:)只要你在索引列上使用了表达式(函数调用,计算)(即所谓的筛选参数(Search Argument),数据库引擎必须去扫描那个索引,而不是进行查找操作。

解决方法

在执行计划里为了获得可扩展的查找操作,你必须要换种方式重写你的查询来避免DATEPART函数的调用:

1 -- Results in an Index Seek
2 SELECT * FROM Sales.SalesOrderHeader
3 WHERE OrderDate >= ‘20050701‘ AND OrderDate < ‘20050801‘
4 GO

从重写的查询可以看到,查询返回同样的结果,但我们已经剔除了DATEPART函数的调用。当你查看执行计划时,你会看到SQL Server进行了查找操作——在那个情况下,这个是所谓的局部范围扫描(Partial Range Scan):SQL Server查找到第1个值,然后扫描到请求范围的最有值。如果你想在索引列上下文调用函数,你必须保证在查询里,这些函数调用的执行在你列的右侧。我们来看一个具体的例子。下面查询把CreditCardID索引列转化为CHAR(4)数据类型:

1 -- Results in an Index Scan
2 SELECT * FROM Sales.SalesOrderHeader
3 WHERE CAST(CreditCardID AS CHAR(4)) = ‘1347‘
4 GO

当你仔细看执行计划时,你会看到SQL Server再次扫描整个非聚集索引。如果你的表越来越大,这是真不能扩展的。如果你在查询里在你索引列的右侧执行转化,你就可以在索引列上剔除函数调用,SQL Server就可以进行查找操作:

1 -- Results in an Index Seek
2 SELECT * FROM Sales.SalesOrderHeader
3 WHERE CreditCardID = CAST(‘1347‘ AS INT)
4 GO

小结

从这篇文章里,你可以看到,在你的索引列里不直接调用任何函数或间接调用函数是非常重要的。不然的话SQL Server会扫描你的索引,而不是进行高效的查找操作。而且当你表越来越大时,扫描从不扩展。

如果你碰到这个特殊行为的其他好例子,想分享的话,欢迎留言。

感谢关注。

时间: 2024-10-13 16:36:53

使用正确的筛选参数来提高查询性能的相关文章

[Oracle][Performance]善用Materialized View提高查询性能#3 Query Rewrite

早期无query rewrite技术,DBACreate中继table提高前端查询性能,但前端程序也需要修改相关Sql statement(牵一发动全身) 可说相当麻烦,如果需求量少倒还好,但量大的话我想DBA这工作应该没人会想做的(事多钱少责任大~> 这篇就来看看Oracle query rewriete技术所带来的改善(MSSQL2005/2008也有应用) 文章均为自己见解,如有错误还请指教 Overview 当现有的Materialized views被用来满足请求时,查询优化器可以自动

SQL Server-聚焦过滤索引提高查询性能(十)

前言 这一节我们还是继续讲讲索引知识,前面我们聚集索引.非聚集索引以及覆盖索引等,在这其中还有一个过滤索引,通过索引过滤我们也能提高查询性能,简短的内容,深入的理解. 过滤索引,在查询条件上创建非聚集索引(1) 过滤索引是SQL 2008的新特性,被应用在表中的部分行,所以利用过滤索引能够提高查询,相对于全表扫描它能减少索引维护和索引存储的代价.当我们在索引上应用WHERE条件时就是过滤索引.也就是满足如下格式: CREATE NONCLUSTERED INDEX <index name> O

Oracle 提高查询性能(基础)

#1,选择最有效的表名顺序 Oracle解析器总是按照从右至左的顺序处理FROM后面的表,因此FROM最右边的表将会被当做驱动表优先处理,当存在多个表关联时,应当使用记录少的表当做驱动表.如果关联的表多的话,则用交叉表作为驱动表. #2,select中避免使用'*'. #3,  减少数据库访问的次数 每当执行一条SQL语句,Oracle 需要完成大量的内部操作,象解析SQL语句,估算索引的利用率,绑定变量, 读数据块等等.由此可 见,减少访问数据库的次数,实际上是降低了数据库系统开销 #4, 用

MySQL查询缓存设置 提高MySQL查询性能

首先看看MSYQL逻辑框架:图片来自高性能mysql 如果使用了QueryCache,当查询接收到一个和之前同样的查询,服务器将会从查询缓存中检索结果,而不是再次分析和执行相同的查询.这样就能大大提高查询性能. 打开查询缓存,要通过几个步骤来设置: 虽然你设置mysql允许查询缓存,但是如果你设置的查询缓存大小为了0,这和没有允许没什么区别. 所以必须是几个步骤的设置才能真正打开查询缓存这个功能. 下面演示最常用的设置查询缓存 一. query_cache_type 使用查询缓存的方式 一般,我

聚焦-移除Bookmark Lookup、RID Lookup、Key Lookup提高SQL查询性能(六)

前言 前面几节都是讲的基础内容,本节我们讲讲索引性能优化,当对大数据进行处理时首先想到的就是索引,一旦遇到这样的问题则手忙脚乱,各种查资料,为何平常不扎实基本功呢,我们由浅入深,简短的内容,深入的理解,而非一上来就把问题给框死,立马给出解决方案,抛出问题,再到解决问题,你GET了没有. Bookmark Lookup.RID Lookup.Key Lookup定义 一说到这三者,如果对索引研究不深的童鞋估计是懵逼的,什么玩意,我们姑且将上面三者翻译为:标签查找.行ID查找.键查找.标签查找和键查

MySQL查询缓存设置提高MySQL查询性能

首先看看MSYQL逻辑框架:图片来自高性能mysql 如果使用了QueryCache,当查询接收到一个和之前同样的查询,服务器将会从查询缓存中检索结果,而不是再次分析和执行相同的查询.这样就能大大提高查询性能. 打开查询缓存,要通过几个步骤来设置: 虽然你设置mysql允许查询缓存,但是如果你设置的查询缓存大小为了0,这和没有允许没什么区别. 所以必须是几个步骤的设置才能真正打开查询缓存这个功能. 下面演示最常用的设置查询缓存 一. query_cache_type 使用查询缓存的方式 一般,我

重建索引提高查询效率

sqlserver重建(rebuild)索引可以提高查询速度 当随着表的数据量不断增长,很多存储的数据进行了不适当的跨页(sqlserver中存储的最小单位是页,页是不不可再分的),会产生很多索引的碎片.这时候需要重建索引来提高查询性能   SQL Server 2005在硬盘中用8KB页面在数据库文件内存放数据.缺省情况下这些页面及其包含的数据是无组织的.为了使混乱变为有序,就要生成索引.生成索引后,就有了索引页和数据页之分:数据页用来保存用户写入的数据信息:索引页存放用于检索列的数据值清单(

SQL Server 查询性能优化——创建索引原则(一)

索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引就越好.索引建少了,用WHERE子句找数据效率低,不利于查找数据.索引建多了,不利于新增.修改和删除等操作,因为做这些操作时,SQL SERVER除了要更新数据表本身,还要连带地立即更新所有的相关索引,而且过多的索引也会浪费硬盘空间.因此要建得恰到好处,这就需要经验了. 一:索引的基本目的 索引的基

SQL Server-聚焦计算列或计算列持久化查询性能(二十二)

前言 上一节我们详细讲解了计算列以及计算列持久化的问题,本节我们依然如前面讲解来看看二者查询性能问题,简短的内容,深入的理解,Always to review the basics. 持久化计算列比非持久化计算列性能要好 我们开始创建两个一样的表并都插入100条数据来进行比较,对于计算列我们重新进行创建计算列和非计算列持久化. CREATE TABLE [dbo].[ComputeColumnCompare] (ID INT, FirstName VARCHAR(100), LastName C