使用 varchar(max) 进行慢速“选择”查询

Posted

技术标签:

【中文标题】使用 varchar(max) 进行慢速“选择”查询【英文标题】:Slow "Select" Query with varchar(max) 【发布时间】:2012-05-29 06:47:30 【问题描述】:

我有一张 500 行的小桌子。 该表有 10 列,包括 1 个 varchar(max) 列。

当我执行这个查询时:

SELECT TOP 36 *
FROM MyTable
WHERE (Column1 = Value1)

它在 3 分钟内检索了大约 36 行。 varchar(max) 列每行包含 3000 个字符。

如果我尝试只检索少一行:

SELECT TOP 35 *
FROM MyTable
WHERE (Column1 = Value1)

然后查询在 0 秒内检索 35 行。

在我的客户统计数据中,从服务器收到的字节数:

95 292 表示查询在 0 秒内检索数据

查询在 3 分钟内检索数据超过 200 000 000

你知道它是从哪里来的吗?

编辑 --- 这是我的真实代码:

select top 36 *
from Snapshots
where ExamId = 212

select top 35 *
from Snapshots
where ExamId = 212

编辑 --- 有关客户统计的更多信息

变化很大的两个统计数据是:

从服务器接收的字节数:66 038 Vs 超过 2 000 000

从服务器 30 Vs 11000 收到的 TDS 数据包

【问题讨论】:

如果问题已经存在,请发送查询计划。 @Toc 你解决了吗?我正在运行完全相同的问题。只有 10 条记录,1 列带有 nvarchar(max) 和一些数据,但没有什么疯狂的。完成前 1 名需要 3 分钟。 【参考方案1】:

使用Index 代替ExamId 也使用select field1,field2,etc 代替select * ...

【讨论】:

试过了。不会改变任何东西【参考方案2】:

我不确定,但试试这个:

select * from Snapshots where ExamId = (select top 36 ExamId from Snapshots where ExamId = 212)

【讨论】:

我试过了(并用“in”替换了“=”),但没有任何改变【参考方案3】:

您的执行时间应该非常短,而 fetch 则要长得多。 从 SELECT TOP 语句中删除 varchar(max) 并仅在您特别需要时检索这些值。

【讨论】:

【参考方案4】:

在运行 SELECT 查询之前包含 SET STATISTICS IO ON 并提供输出。此外,您能否发布来自 2 个不同查询的查询计划,因为这将大大有助于解释差异是什么。您可以使用https://www.brentozar.com/pastetheplan/ 上传并提供链接。

您的TOP 也没有匹配的ORDER BY,因此您无法保证返回的前35 或36 行的顺序。这意味着 35 行可能不会全部包含在 36 行中,您可能返回的数据量大不相同。

最后,还可以尝试在 SSMS 中通过查询启用 Client Statistics - 这将显示延迟是在服务器端还是在向您返回结果集时的全部延迟。

【讨论】:

【参考方案5】:

如果没有完整的表描述作为 DDL 语句 (CREATE TABLE...) 和索引,则很难回答。

一个重要的问题是:您在创建表时使用“指令”TEXTIMAGE_ON 吗?这会将 LOB 存储与关系数据分开,以避免行溢出存储...

【讨论】:

【参考方案6】:

Varchar(max) 不能成为索引键的一部分,除了这个其他主要缺点之外,它不能作为连续的内存区域在内部存储,因为它们可能会增长到 2Gb。因此,为了提高性能,您需要避免它。

【讨论】:

请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。【参考方案7】:

正如其他人所说,您应该扔 schema (datatype+existing index) of Snapshot table。

snapshot 表中,我相信examid 是非聚集索引,它不是唯一的。 一个examid 有很多记录。快照表必须有任何PK 列。

Top 子句应始终与Order by 子句一起使用。没有Order by 子句的Top 子句为Non Determinstic。 在什么基础上它将选择Top N。 所以知道快照的模式然后决定正确的索引。

使用Order by 子句也可以是Non Determinstic 但这是另一个讨论。

你可以试试这个,

create  table #temp(PKID int)

insert into #temp(pkid)
select top 36 pkid
from dbo.Snapshots
where ExamId = 212

那么你就可以这样做了,

select col1,col2,col3,col4
from dbo.Snapshots S
where exists(select 1 from #temp t where t.pkid=s.pkid)

现在你的主要问题和问题,

为什么 0 秒检索 35 行,3 分钟检索 36 行。

我会很快写到这里。同时我正在等待快照表的完整结构。

【讨论】:

以上是关于使用 varchar(max) 进行慢速“选择”查询的主要内容,如果未能解决你的问题,请参考以下文章

varchar(max) MS SQL Server 2000,有问题吗?

选择转换为小数的最大 varchar

SQL Server Always Encrypted:操作数类型冲突:varchar 与 varchar(max) 不兼容

查阻塞

Varchar(255) 到 Varchar(MAX)

使用内部选择慢速 MySQL 连接