假设我只有一张桌子
CREATE TABLE Ticket (
TicketId int NOT NULL,
InsertDateTime datetime NOT NULL,
SiteId int NOT NULL,
StatusId tinyint NOT NULL,
AssignedId int NULL,
ReportedById int NOT NULL,
CategoryId int NULL
);
在此示例中TicketId
是主键。
我希望用户能够针对此表创建“部分即席”查询。我之所以说是部分原因是因为查询的某些部分将始终固定:
- 该查询将始终对
InsertDateTime
- 查询将始终
ORDER BY InsertDateTime DESC
- 查询将分页结果
用户可以选择对其他任何列进行过滤。它们可以过滤一个,一个或多个。并且对于每个列,用户可以从一组值中进行选择,这些值将被用作析取。例如:
SELECT
TicketId
FROM (
SELECT
TicketId,
ROW_NUMBER() OVER(ORDER BY InsertDateTime DESC) as RowNum
FROM Ticket
WHERE InsertDateTime >= '2013-01-01' AND InsertDateTime < '2013-02-01'
AND StatusId IN (1,2,3)
AND (CategoryId IN (10,11) OR CategoryId IS NULL)
) _
WHERE RowNum BETWEEN 1 AND 100;
现在假设表有100,000,000行。
我能提出的最好的建议是一个涵盖索引,其中包含每个“可选”列:
CREATE NONCLUSTERED INDEX IX_Ticket_Covering ON Ticket (
InsertDateTime DESC
) INCLUDE (
SiteId, StatusId, AssignedId, ReportedById, CategoryId
);
这给了我一个查询计划,如下所示:
- 选择
- 过滤
- 最佳
- 序列项目(计算标量)
- 分割
- 索引搜寻
- 分割
- 序列项目(计算标量)
- 最佳
- 过滤
好像还不错 大约80%-90%的成本来自Index Seek操作,这是理想的选择。
是否有更好的策略来实施这种搜索?
我不一定要将可选的筛选工作卸载到客户端,因为在某些情况下,“固定”部分的结果集可能是100s或1000s。然后,客户端还将负责排序和分页,这可能会给客户端带来太多工作。
是否可以将子查询放入临时表或表变量中并以这种方式构建?在我的桌子较大时,有时会被子查询困扰。涵盖索引只能带您走远。
—
女武神
@Valkyrie效率极低。还应考虑到该查询的变体(不同的参数和不同的可选where子句)可能整天每秒执行几次,并且平均需要在不到100ms的时间内返回结果。我们已经做到了,并且现在还可以。我只是在寻找有关如何继续提高性能以实现可伸缩性的想法。
—
约瑟夫·戴格尔,2013年
您关心多少使用存储空间?
—
乔恩·塞格尔
@JonSeigel这取决于多少...但是我想看看任何建议
—
Joseph Daigle
您要获取结果第二页的方法/查询是什么?
—
ypercubeᵀᴹ
RowNum BETWEEN 101 AND 200
?