2009-06-03 99 views
1

我在Microsoft SQL Server 2008中遇到了一个奇怪的问题。 我有一个大型数据库(20 GB),包含大约10个表,我试图就如何正确地创建索引提出一个观点。SQL Server 2008性能:没有索引与不良索引?

这是我的问题:在一些嵌套查询我得到更快的结果没有使用索引!它接近(一两秒),但在某些情况下,根本不使用索引似乎会使这些查询运行得更快......我正在运行一个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)。

最后,识别符表已超过万个条目,而车表有两三万

+0

感谢所有答案的家伙! 不幸的是,SQL Server认为数据库应该被彻底恢复,所以我很害怕暂时被锁定。 PS:我还删除了“无索引”方法中的主键,但在索引很差的索引中重建了它们 – 2009-06-03 14:58:02

回答

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)

+0

想到这一点,尽管自创建索引以来没有执行插入操作 – 2009-06-03 16:09:20

+0

关于覆盖索引,如果我搜索my_string1和my_string2,可以涵盖索引提供了答案? – 2009-06-03 16:10:20

+1

它有时会使用索引,尽管my_string1和my_string2不在索引的开头,它必须是索引扫描。想象一下,在电话簿中寻找有“a”作为他们姓氏的第二个字母的人。跳到可能具有该部分(“aa”,“ba”等)的每个部分,而不是扫描整个电话簿的速度会更快,但速度并不像通过首字母查找名称那么快。 – 2009-06-03 16:54:00

0

检查执行计划,看它是否正在使用这些指标,你“知道”一个是坏?

通常,索引会减慢写入数据的速度,并有助于加速读取数据。

所以是的,我同意你的看法。它应该从来没有比根本没有索引慢。

1

通常,SQL Server在决定使用哪种索引(如果有的话)以最快的方式检索数据方面做得很好。很多时候它会决定不使用任何索引,因为它可以更快地从小表中检索少量数据,而不必离开索引(在某些情况下)。

这听起来像你的情况SQL可能不会采取最优路线。有很多严重创建的索引可能会导致它选择错误的路线来获取数据。

我会建议查看管理工作室的查询计划,以检查其使用的索引和时间正在采取。这应该给你一个好主意从哪里开始。

另一个需要注意的是,也许是这些指标已经得到碎片随着时间的推移,现在未能发挥最好的,这也许值得一试这一点,如果需要重建他们中的一些。

1

索引直到您有很多记录才真正没有任何好处。我说很多,因为我真的不知道这个转折点是什么......它取决于具体的应用和情况。

SQL Server需要时间才能使用索引。如果那个时间超过了好处......这在子查询中尤其如此,其中小的差异将会倍增。

如果在没有索引的情况下效果更好,则省略索引。

+0

对于SQL 2000,它大约有134行。并不是那么多。 – gbn 2009-06-03 14:43:26

1

尝试DBCC FREEPROCCACHE以清除执行计划缓存。

+0

@ gbn + 1:迄今为止最明智的评论。 1秒的差异可能是初始查询的编译成本:-)我还建议你(SET STATISTICS IO ON)开始查看逻辑和物理读取的数量以及(SET STATISTICS TIME ON),以准确地监视时间。 – 2009-06-03 14:44:53

+0

添加到查询,只是等待恢复....该死,糟糕的时机:S – 2009-06-03 15:04:34

1

这是一个空洞的猜测。也许如果你有很多索引,SQL Server会花时间分析和挑选一个,然后拒绝所有这些索引。如果你没有索引,引擎就不用浪费时间进行这个审查过程。

这个审查过程实际需要多长时间,我不知道。

1

对于某些查询,直接从表中读取(聚簇索引扫描)要快于读取索引并从表中读取记录(索引扫描+书签查找)。

请考虑记录与数据页中的其他记录一起存在。 Datapage是IO的基本单位。如果直接读取表格,则可以获得10个记录,其中包含1个IO的成本。如果直接读取索引,然后从表中提取记录,则必须为每条记录支付1 IO。

通常SQL服务器非常擅长挑选访问表的最佳方式(直接与索引)。您的查询中可能有一些盲目优化器。查询提示可以指示优化器在错误时使用索引。加入提示可以改变表的访问顺序或方法。表变量被优化器认为有0条记录,所以如果你有一个大的表变量 - 优化器可能会选择一个坏计划。

还有一件事要注意 - varchar vs nvarchar。确保所有参数与目标列的类型相同。在发生类型不匹配的情况下,SQL Server会将的整个索引转换为参数的类型。

+0

嗯,我看到了,虽然我没有使用不同类型的列和表变量。尽管 – 2009-06-03 15:07:07

0

SQL服务器实际上为您创建了一些索引(例如,在主键上)。

索引可能变成碎片。

索引过多会一直降低性能(有上为什么不能索引在数据库中每一个山坳常见问题解答)

也有s个ome situations where indexes will always be slower

+0

已被杀死,但主键和索引都是“新建”的:S – 2009-06-03 15:07:37

0

运行:

SET SHOWPLAN_ALL ON 

,然后运行使用和不使用索引使用您的查询,这将让你看看是否有任何正在使用什么指标,这里的“工作”是在等

0

没有SQL服务器决定使用一个索引来加速查询之前分析这两个指标和统计数据。运行非索引版本完全有可能比索引版本更快。

有几件事情来尝试

  1. 确保创建和重建索引,重新组织(整理)。

  2. 确保自动创建统计信息被打开。

  3. 尝试使用SQL事件探查器捕获调整配置文件,然后使用数据库引擎优化顾问创建索引。

令人惊讶的是,Sql管理的MS Press考试书很好地解释了索引和统计数据。在这本书的读者亚马逊预览的内容

见第4章表

Amazon Reader of Sql 2008 MCTS Exam Book

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 
+0

完成,检查出来 – 2009-06-03 15:50:09

+0

会做什么,还在等待恢复...加耶 – 2009-06-03 16:50:23