sql-server – 强制流不同

前端之家收集整理的这篇文章主要介绍了sql-server – 强制流不同前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有这样一张桌子:
CREATE TABLE Updates
(
    UpdateId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,ObjectId INT NOT NULL
)

基本上跟踪具有增加ID的对象的更新.

此表的使用者将选择100个不同对象ID的块,按UpdateId排序并从特定的UpdateId开始.基本上,跟踪它停止的位置,然后查询任何更新.

我发现这是一个有趣的优化问题,因为我只能通过编写因索引而碰巧做我想要的查询生成最佳的查询计划,但不能保证我想要的:

SELECT DISTINCT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId

其中@fromUpdateId是存储过程参数.

有一个计划:

SELECT <- TOP <- Hash match (flow distinct,100 rows touched) <- Index seek

由于正在使用的UpdateId索引上的搜索,结果已经很好并且从我想要的从最低到最高的更新ID排序.这会产生一个流量不同的计划,这就是我想要的.但顺序显然不是保证行为,所以我不想使用它.

这个技巧也会产生相同的查询计划(尽管有一个冗余的TOP):

WITH ids AS
(
    SELECT ObjectId
    FROM Updates
    WHERE UpdateId > @fromUpdateId
    ORDER BY UpdateId OFFSET 0 ROWS
)
SELECT DISTINCT TOP 100 ObjectId FROM ids

虽然,我不确定(并且怀疑不是)这是否真的能保证订购.

我希望sql Server能够简化智能化的一个问题就是这样,但最终会产生一个非常糟糕的查询计划:

SELECT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
GROUP BY ObjectId
ORDER BY MIN(UpdateId)

有一个计划:

SELECT <- Top N Sort <- Hash Match aggregate (50,000+ rows touched) <- Index Seek

我正在尝试找到一种方法生成一个最佳计划,在UpdateId上使用索引查找,并且使用不同的流来删除重复的ObjectId.有任何想法吗?

Sample data如果你想要它.对象很少会有一个以上的更新,并且在一组100行中几乎不会有多个,这就是为什么我在流量不同之后,除非有一些我不知道的更好的东西?但是,无法保证单个ObjectId在表中的行数不会超过100行.该表有超过1,000,000行,预计将迅速增长.

假设用户有另一种方法可以找到合适的下一个@fromUpdateId.无需在此查询中返回它.

解决方法

由于Hash Match Flow Distinct运算符不是保持顺序,因此sql Server优化程序无法生成您所需的保证所执行的执行计划.

Though,I’m not sure (and suspect not) if this truly guarantees ordering.

在许多情况下,您可能会观察到订单保留,但这是一个实施细节;没有保证,所以你不能依赖它.与往常一样,演示顺序只能由顶级ORDER BY子句保证.

下面的脚本显示Hash Match Flow Distinct不保留顺序.它设置了相关表格,并在两列中匹配数字1-50,000:

IF OBJECT_ID(N'dbo.Updates',N'U') IS NOT NULL
    DROP TABLE dbo.Updates;
GO
CREATE TABLE Updates
(
    UpdateId INT NOT NULL IDENTITY(1,1),ObjectId INT NOT NULL,CONSTRAINT PK_Updates_UpdateId PRIMARY KEY (UpdateId)
);
GO
INSERT dbo.Updates (ObjectId)
SELECT TOP (50000)
    ObjectId =
        ROW_NUMBER() OVER (
            ORDER BY C1.[object_id]) 
FROM sys.columns AS C1
CROSS JOIN sys.columns AS C2
ORDER BY
    ObjectId;

测试查询是:

DECLARE @Rows bigint = 50000;

-- Optimized for 1 row,but will be 50,000 when executed
SELECT DISTINCT TOP (@Rows)
    U.ObjectId 
FROM dbo.Updates AS U
WHERE 
    U.UpdateId > 0
OPTION (OPTIMIZE FOR (@Rows = 1));

估计的计划显示索引搜索和流量不同:

输出肯定有序开始:

……但是进一步下降的价值开始“失踪”:

……最终:

在这种特殊情况下的解释是哈希运算符溢出:

分区溢出后,散列到同一分区的所有行也会溢出.稍后处理溢出的分区,从而打破了遇到的不同值将按接收顺序立即发出的期望.

有许多方法可以编写有效的查询生成所需的有序结果,例如递归或使用游标.但是,使用Hash Match Flow Distinct无法完成.

猜你在找的MsSQL相关文章