2

我有一个表 mytable ,其中包含一些列,包括列datekey(这是 adate并具有索引)、一列contents是 avarbinary(max)和一列stringhash是 a varchar(100)。和一起构成表stringhashdatekey主键。一切都在我的本地机器上运行。

跑步

SELECT TOP 1 * FROM mytable where datekey='2012-12-05'

返回 0 行并花费 0 秒。但是如果我添加一个datalength条件:

SELECT TOP 1 * FROM mytable where datekey='2012-12-05' and datalength(contents)=0

它运行了很长时间并且在我放弃等待之前没有返回任何东西。

我的问题: 为什么?我如何找出为什么这需要这么长时间?


这是我到目前为止检查的内容:

当我单击“显示估计的执行计划”时,它也需要很长时间并且在我放弃等待之前没有返回任何内容。

如果我做

SELECT TOP 1000 datalength(contents) FROM mytable order by datalength(contents) desc

它需要 7 秒并返回一个列表 4228081、4218689 等。

exec sp_spaceused 'mytable'

返回

rows        reserved     data         index_size  unused
564019      50755752 KB  50705672 KB  42928 KB    7152 KB

所以表在 50 GB 时相当大。跑步

SELECT TOP 1000 * FROM mytable

需要 26 秒。

sqlservr.exe 进程大约为 6 GB,这是我为数据库设置的限制。

4

3 回答 3

4

这需要很长时间,因为您的查询需要为每一行评估 DATALENGTH,然后对结果进行排序,然后才能返回第一条记录。如果字段的 DATALENGTH(或者它是否包含任何值)是您可能会重复查询的内容,我建议您使用一个额外的索引字段(可能是一个持久计算字段)来保存结果并对其进行搜索。

于 2012-12-07T20:22:37.087 回答
1

这篇旧的msdn 博客文章似乎同意datalength对每一行进行评估的@MartW 答案。但是最好了解“评估”的真正含义以及性能下降的真正根源是什么。

如问题中所述,列中每个值的大小contents可能很大。这意味着每个大于 ~8Kb 的值都存储在特殊的 LOB 存储中。因此,考虑到其他列的大小,很明显,该表占用的大部分空间都被此 LOB 存储占用,即大约 50Gb。

即使contents已经评估了每一行的列长度,这在上面链接的帖子中得到了证明,它仍然存储在 LOB 中。所以引擎仍然需要读取 LOB 存储的某些部分来执行查询。

If LOB-storage isn't in RAM at the time of a query execution then we need to read it from a disk, which is of course much slower than from RAM. Also possibly the read of LOB-parts is rather randomized than linear which is even more slow as it tends to raise the whole number of memory-blocks needed to be read from a disk.

于 2017-08-10T13:28:29.623 回答
0

目前它可能不会使用主键,因为在 datekey 列之前包含 stringhash 列。尝试添加仅包含 datekey 列的附加索引。一旦创建了该密钥,如果它仍然很慢,您还可以尝试查询提示,例如:

SELECT TOP 1 * FROM mytable where datekey='2012-12-05' and datalength(contents)=0 WITH INDEX = IX_datekey

您还可以创建一个单独的长度列,该列在您的应用程序或插入/更新触发器中更新。

于 2012-12-06T11:33:06.620 回答