使用 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 b
y 子句一起使用。没有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,有问题吗?
SQL Server Always Encrypted:操作数类型冲突:varchar 与 varchar(max) 不兼容