1

今天我只是看了一些评论,我做了一些实验。我想象了一个存储一些坐标的系统。

情况如下:

我有两张桌子,第一张是:

CREATE TABLE Points
(
ID int IDENTITY(1,1) PRIMARY KEY,
X int,
Y int,
Name varchar(20),
Created datetime
)

它只是存储坐标(100 万行)。第二个是一个帮助表,存储一些我们说经常使用的点进行选择(大约 1100 行)

CREATE TABLE PointSearchHelper
(
X int,
Y int
)

到目前为止一切顺利。

我想做一个简单的选择:

SELECT p.* FROM Points p 
INNER JOIN PointSearchHelper h
ON p.X = h.X AND p.Y = h.Y

我运行脚本,它平均在280 毫秒左右获得 1100 行。

当我检查我看到的执行计划时,SQL Server 2008 R2 推荐了一个索引(谁会想到?;)):

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[Points] ([X], [Y])
INCLUDE ([ID], [Name], [Created])

这是一个完整的表索引,包含每一列。它的大小是“巨大的”比较,我现在存储数据两次!

所以查询 no 要快得多!大约是75 毫秒(!) 非常大的改进我需要几乎两倍的空间来进行这种改进。

我的问题很简单:有没有办法告诉列上的 SQL Server 如何存储值或任何其他技巧来避免双重存储?

更新:

换句话说:是否有任何技巧可以避免具有相同性能的“完整索引”?

4

5 回答 5

2

将您的 PointSearchHelper 表更改为仅使用索引而不是 x、y 坐标:

create table PointSearchHelper . . .
    points_id int not null primary key

当您进行连接时,请改为在 points_id 上进行。这应该减少空间并提高性能。

PS。我遇到了最奇怪的问题。向代码添加开放括号会导致加载答案时出错。

于 2012-08-30T18:36:13.923 回答
1

你的 X+Y 对是独一无二的吗?
如果是,您可以考虑删除标识列并在 X+Y 对上创建复合主键。这将消除对附加索引的需求,并可能进一步加快您的查询速度。

于 2012-08-30T18:12:18.523 回答
1

它在很大程度上取决于对该表的其他查询,但如果您不想拥有完整索引,则可以从 ID 中删除主键,而是将主键(和聚集索引)放在(X, Y)

这样做会通过 X 和 Y 值将数据存储在表中,因此这个特定的查询会更快,并且只需要使用新创建的聚集索引。

Points如果您对使用 ID in 子句的表进行查询,您将不得不寻找可能产生的性能问题WHERE,因为该列将不再像现在一样按 ASC 排序存储。如果您发现您的大多数查询是通过 X、Y 值查询此表,您可以在开发服务器中测试此更改并查看它是否适合您的需要。

于 2012-08-30T18:12:47.867 回答
1

当您创建索引而不包含非键值时,您会得到什么结果?它可能接近您使用完整索引获得的速度。

此外,如果 X、Y 坐标在 Points 中保证唯一,那么您可以考虑删除 ID 列并直接在 (X, Y) 上创建主键。这将为您节省一些空间以及索引该列的开销。

于 2012-08-30T18:14:26.130 回答
0

我想在这里更容易回答答案,因为我做了“功课”,我很惊讶:

第一的:

没有包含非键值的情况下更改 INDEX -> 这没有帮助,性能大约是 280 毫秒,就像没有完整索引的正常情况一样。

第二:

删除 ID 列,使X + Y 作为主键(假设这些点是唯一的)并在 X + Y 上的 PointSearchHelper 表上创建另一个主键索引。该解决方案让我感到惊讶,因为当时执行计划同时使用了两个索引,但速度也在 280 毫秒左右。所以它根本没有帮助

第三:

删除存储 X 和 Y 的 ID,假设当我保存值时围绕它做一些逻辑,我检查这些记录的主键 ID 是什么。这样只有两个索引,Points 和 PointHelperSearch 上还有两个主键索引。(我可以在 exectuin 计划中看到它们,它们都被使用了。)它做到了!速度约为 60-70 毫秒。所以这里是诀窍。

现在,我想知道SecondThird之间有什么区别。是否计数了这么多毫秒,以至于有两个数字而不是一个?

于 2012-08-31T05:44:02.927 回答