sql-server-2008 – SQL Server LEFT JOIN无法匹配没有JOIN提示的行

我有什么看似腐败的指数?

这是正在发生的事情.我有两个表函数,第一个是一组案例,第二个是一组有意识的日期.这两组具有1(案例)到0或1(知悉日期)关系.通常我会查询它们;

SELECT c.CaseID, a.AwareDate  
FROM Cases(@date) AS c  
LEFT JOIN AwareDates(@date) AS a ON c.CaseID = a.CaseID;

麻烦的是,并非AwareDates中匹配的所有行似乎都是JOIN.如果我添加一个连接提示,他们就会这样做.说;

SELECT c.CaseID, a.AwareDate  
FROM Cases(@date) AS c  
LEFT MERGE JOIN AwareDates(@date) AS a ON c.CaseID = a.CaseID;

我从查询计划中注意到的是,添加联接提示会在联接之前添加一种AwareDate数据,否则就不存在.此外,查询计划程序在没有提示时将连接翻转到RIGHT OUTER JOIN,当然保持LEFT JOIN存在提示的位置.

我没有检测到错误,我做了以下事情;

DBCC UPDATEUSAGE (0) WITH INFO_MESSAGES, COUNT_ROWS;  
EXECUTE sp_updatestats 'resample';  
DBCC CHECKDB (0) WITH ALL_ERRORMSGS, EXTENDED_LOGICAL_CHECKS;  

我很难过……任何想法?

以下是UDF定义

ALTER FUNCTION dbo.Cases( @day date ) RETURNS TABLE
WITH SCHEMABINDING
AS RETURN (
SELECT 
    CaseID -- other 42 columns ommitted
FROM (
    SELECT
        ROW_NUMBER() OVER (PARTITION BY CaseID ORDER BY UpdateDate DESC, UpdateNumber DESC) AS RecordAge,
        CaseID, 
        Action
    FROM
        dbo.CaseAudit
    WHERE
        convert(date,UpdateDate) <= @day
    ) AS History
WHERE
    RecordAge = 1                    -- only the most current record version
    AND isnull(Action,'') != N'DEL'  -- only include cases that have not been deleted
)
ALTER FUNCTION dbo.AwareDates( @day date ) RETURNS TABLE
WITH SCHEMABINDING
AS RETURN (
WITH 
    History AS (
        SELECT row_number() OVER (PARTITION BY CaseID, ContactID ORDER BY UpdateDate DESC, UpdateNumber DESC) AS RecordAge,
            CaseID, InfoReceived, ReceiveDate, ResetClock, Action
        FROM dbo.ContactLogAudit WITH (NOLOCK)
        WHERE convert(date,UpdateDate) <= @day
        ),
    Notes AS (
        SELECT 
            CaseID,
            convert(date,ReceiveDate,112) AS ReceiveDate,
            ResetClock
        FROM History 
        WHERE RecordAge = 1                -- only the most current record version
        AND isnull(Action,'') != N'DEL'    -- only include notes that have not been deleted
        AND InfoReceived = N'Y'            -- only include notes that have Info Rec'd checked 
        AND len(ReceiveDate) = 8 AND isnumeric(ReceiveDate) = 1 AND isdate(ReceiveDate) = 1 -- only include those with a valid aware date
        ),
    Initials AS (
        SELECT CaseID, min(ReceiveDate) AS ReceiveDate
        FROM Notes 
        GROUP BY CaseID
        ),
    Resets AS (
        SELECT CaseID, max(ReceiveDate) AS ReceiveDate
        FROM Notes 
        WHERE ResetClock = N'Y'
        GROUP BY CaseID
        )
SELECT 
    i.CaseID                              AS CaseID,
    i.ReceiveDate                         AS InitialAwareDate, -- the oldest valid aware date value (must have AE Info Reveived checked and a received date)
    coalesce(r.ReceiveDate,i.ReceiveDate) AS AwareDate  -- either the newest valid aware date value with the Reset Clock checked, otherwise the initial aware date value
FROM Initials AS i
LEFT JOIN Resets AS r 
    ON i.CaseID = r.CaseID
);

我进一步发现,如果我删除“WITH(NOLOCK)”表提示,我得到正确的结果.此外,如果向AwareDates UTF添加连接提示,或者甚至在Initials和Resets之间的LEFT JOIN关系上添加COLLATE Latin1_General_BIN.

查询计划行计数 – 没有连接提示(已损坏)

>案例{实际:25,891,估计:19,071.9}
> AwareDates {实际:24,693,估计:1,463.09}

>姓名缩写{实际:24,693,估计:1,463.09}
>休息{实际:985,估计:33.2671}

> AwareDates匹配join’d结果集中的8,108个Cases行

查询计划行数 – 使用连接提示(工作)

>案例{实际:25,891,估计:19,071.9}
> AwareDates {实际:24,673,估计:1,837.67}

>姓名缩写{实际:24,673,估计:1,837.67}
>休息{实际:982,估计:42.6238}

> AwareDates匹配join’d结果集中的24,673个Cases行

我进一步削弱了问题的范围.我可以;

SELECT * FROM AwareDate(@date);  

SELECT * FROM AwareDate(@date) ORDER BY CaseID;  

具有不同的行数.

最佳答案 您没有指定SQL的特定版本(@@ version),但这似乎与SQL 2008 R2的累积更新6中的
bug that was fixed一样可疑(显然它也适用于SQL 2008).

07001
FIX: You may receive an incorrect result when you run a query that uses the
ROW_NUMBER function together with a left outer join in SQL Server 2008

文章中的示例指定了DISTINCT.然而,这篇文章措辞含糊不清 – 目前尚不清楚你是否需要一个独特的,或者DISTINCT是否是其中一个触发因素.

你的例子没有像文章那样明显,但它似乎是为了提出问题而修改的(即缺少42列).有明显的吗?同样在AwareDates udf中,当我进入Initials CTE时,你会做一个GROUP BY,它可以和DISTINCT具有相同的效果.

UPDATE

@Dennis从您的评论中我仍然无法判断您是使用SQL 20080还是2008 R2.

如果您正在运行2008,知识库文章说“此问题的修复程序首先在SQL Server 2008 Service Pack 1的累积更新11中发布.”所以,发布SP1.

另一方面,如果你正在使用SQL 2008 R2,那么你在CU 6中修复了这是正确的,它是SP1的一部分.但是这个错误似乎已经重新出现了.看看Cumulative update package 4 for SQL Server 2008 R2 Service Pack 1 – SP1发布后.

970198      FIX: You receive an incorrect result when you run a 
            query that uses the row_number function in SQL Server 2008 
            or in SQL Server 2008 R2 

associated KB article MS中删除了对distinct的引用:

Consider the following scenario. You run a query against a table that has a 
clustered index in Microsoft SQL Server 2008 or in Microsoft SQL Server 2008
R2. In the query, you use the row_number function. In this scenario, you 
receive an incorrect result when a parallel execution plan is used for the 
query. If you run the query many times, you may receive different results.

这似乎证实了我之前对KB 2433265的解读 – 措辞暗示不同只是导致行为的许多条件之一.似乎并行执行计划是这次的罪魁祸首.

点赞