我遇到了Microsoft SQL Server 2008中的一个奇怪问题。 我有一个大型数据库(20 GB),大约有10个表,我试图说明如何正确创建索引。
这是我的问题:在一些嵌套查询中,我得到更快的结果没有使用索引!它很接近(一两秒钟),但在某些情况下根本不使用索引似乎使这些查询运行得更快...我在运行脚本之前运行了Checkpoiunt和DBCC dropcleanbuffers来重置缓存,所以我'有点失落。
可能导致这种情况的原因是什么? 我知道索引的构造很差(每个相关字段都考虑一个索引),重点是要证明正确构造它们的重要性,但它应该永远比没有索引慢对吧?对不起?
编辑:这是一个有罪的问题:SET STATISTICS TIME ON
SET STATISTICS IO ON
USE DBX;
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS;
GO
DBCC FREEPROCCACHE;
GO
SELECT * FROM Identifier where CarId in (SELECT CarID from Car where ManufactId = 14) and DataTypeId = 1
标识符表: - IdentifierId int not null - CarId int not null - DataTypeId int not null - 别名nvarchar(300)
车牌表: - CarId int not null - ManufactId int not null - (后面跟着几个字段,所有nvarchar(100)
这些项目符号点中的每一个都有一个索引,以及一次同时存储其中两个索引的索引(例如CarId和DataTypeId)。
最后,标识符表有超过百万个条目,而Car表有两三百万个
答案 0 :(得分:4)
我的猜测是SQL Server错误地决定使用索引,然后强制书签查找*。通常当发生这种情况时(错误使用索引),这是因为表上的统计信息不正确。
如果您刚刚将大量数据加载到一个或多个表中,则尤其会发生这种情况。或者,可能是SQL Server只是搞砸了。发生这种情况的情况非常罕见(我可以指望我在SQL Server的15年职业生涯中不得不强制使用索引的时间),但优化器并不完美。
*书签查找是指SQL Server在索引上找到所需的行,但必须转到实际的数据页以检索不在索引中的其他列。如果结果集返回大量行,则这可能代价高昂,并且聚簇索引扫描可以带来更好的性能。
摆脱书签查找的一种方法是使用覆盖索引 - 一个首先包含过滤列的索引,但是还包括“覆盖”查询中需要的任何其他列。例如:
SELECT
my_string1,
my_string2
FROM
My_Table
WHERE
my_date > '2000-01-01'
覆盖索引将是(my_date,my_string1,my_string2)
答案 1 :(得分:1)
通常,SQL Server在决定使用哪种索引(如果有)以最快的方式检索数据方面做得很好。通常它会决定不使用任何索引,因为它可以更快地从小表中检索少量数据而不会转移到索引(在某些情况下)。
听起来好像在你的情况下SQL可能没有采取最佳路线。拥有大量创建错误的索引可能会导致它选择错误的路由来获取数据。
我建议在管理工作室中查看查询计划,以检查其使用的索引以及时间在哪里。这应该会让你知道从哪里开始。
另一个注意事项是,这些索引可能随着时间的推移而变得支离破碎,现在表现不佳,可能值得检查并在需要时重建其中一些。
答案 2 :(得分:1)
在您拥有许多记录之前,索引确实没有任何好处。我之所以说很多,是因为我真的不知道那点小费是什么......这取决于具体的应用和环境。
SQL Server需要一段时间才能使用索引。如果那个时间超过了这个好处......在子查询中尤其如此,其中一个小的差异会成倍增加。
如果在没有索引的情况下效果更好,请忽略索引。
答案 3 :(得分:1)
尝试DBCC FREEPROCCACHE以清除执行计划缓存。
答案 4 :(得分:1)
这是一个空洞的猜测。也许如果你有很多索引,SQL Server会花时间分析和选择一个,然后拒绝所有索引。如果您没有索引,引擎就不必浪费时间进行审查。
这个审查过程实际需要多长时间,我不知道。
答案 5 :(得分:1)
对于某些查询,直接从表中读取(聚集索引扫描)比读取索引和从表中获取记录(索引扫描+书签查找)更快。
考虑一条记录与数据页中的其他记录一起存在。 Datapage是IO的基本单元。如果直接读取表,则可以获得10条记录,费用为1 IO。如果直接读取索引,然后从表中提取记录,则必须为每条记录支付1 IO。
通常,SQL服务器非常擅长选择访问表的最佳方式(直接与索引)。您的查询中可能存在使优化器变得模糊的内容。查询提示可以指示优化器在错误时使用索引。加入提示可以改变表的访问顺序或方法。表变量被优化器认为有0条记录,因此如果你有一个很大的表变量 - 优化器可能会选择一个糟糕的计划。
还需要注意的一件事 - varchar vs nvarchar。确保所有参数与目标列的类型相同。在某种类型不匹配的情况下,SQL Server会将整个索引转换为参数的类型。
答案 6 :(得分:0)
检查执行计划,看看它是否正在使用您“知道”不好的其中一个索引?
通常,索引会降低写入数据的速度,并有助于加快读取数据的速度。
是的,我同意你的意见。 永远应该比没有索引慢。
答案 7 :(得分:0)
SQL Server实际上为您制作了一些索引(例如,在主键上)。
索引可能会碎片化。
太多的索引总是会降低性能(有关于为什么不对db中的每个col进行索引的常见问题解答)
答案 8 :(得分:0)
运行:
SET SHOWPLAN_ALL ON
然后在使用和不使用索引的情况下运行您的查询,这将让您查看正在使用的索引,“工作”正在进行的位置等。
答案 9 :(得分:0)
在决定使用索引加速查询之前,没有Sql Server分析索引和统计信息。运行非索引版本完全有可能比索引版本更快。
要尝试的一些事情
确保创建和重建索引,并重新组织(碎片整理)。
确保已启用自动创建统计信息。
尝试使用Sql Profiler捕获调优配置文件,然后使用数据库引擎优化顾问创建索引。
令人惊讶的是,用于Sql管理的MS Press Exam book很好地解释了索引和统计数据。
参见本书的亚马逊读者预览中的第4章目录
答案 10 :(得分:0)
对我而言,听起来你的sql编写得非常差,因此没有使用你正在创建的索引。
你可以添加索引,直到你脸红了,但如果你的查询没有经过优化以使用这些索引,那么你就不会获得任何性能提升。
向我们提供您正在使用的查询示例。
...好吗
尝试这一点,看看你是否获得了任何性能提升(使用pk索引)
SELECT i.*
FROM Identifier i
inner join Car c
on i.CarID=c.CarID
where c.ManufactId = 14 and i.DataTypeId = 1