SQL:按性能嵌套选择与双联接

时间:2019-06-30 09:41:45

标签: sql sql-server performance join select

我有一个基于存储过程的报告,我需要在输出中添加用户名。

在我的系统中,两个用户可以是交易的所有者。

此外,在我的系统中,用户信息存储在不同的数据库中。

因此,我仅看到两种添加用户名的方法:

案例1

SELECT 
    E.*,
    CASE WHEN (E.UserDetailsId IS NULL AND E.UserDetailsId2 IS NULL)
            THEN 'N/A'
        ELSE
        (SELECT CONCAT(FirstName, ' ', LastName) AS UserName 
            FROM UserDb.dbo.UserDetails WHERE (
            (UserDetailsId IS NOT NULL AND UserDetailsId = E.UserDetailsId)
            OR 
            (UserDetailsId2 IS NOT NULL AND UserDetailsId2 = E.UserDetailsId)
            )
    END AS UserName,
FROM 
    TransactionDetail E
WHERE 
    E.TransactionDetailTypeId = @TypeId

案例2

SELECT 
    E.*,
    CASE WHEN (E.UserDetailsId IS NULL AND E.UserDetailsId2 IS NULL)
            THEN 'N/A'
        ELSE
    CASE WHEN (E.UserDetailsId IS NOT NULL)
        THEN CONCAT(UD.FirstName, ' ', UD.LastName)
    CASE WHEN (E.UserDetailsId2 IS NOT NULL)
        THEN CONCAT(UD2.FirstName, ' ', UD2.LastName)
    END AS UserName
FROM 
    TransactionDetail E
    JOIN UserDb.dbo.UserDetails UD ON UD.UserDetailsId = E.UserDetailsId
    JOIN UserDb.dbo.UserDetails UD2 ON UD2.UserDetailsId = E.UserDetailsId
WHERE 
    E.TransactionDetailTypeId = @TypeId

我尝试在本地计算机上进行性能测试,该测试具有100万个测试事务和1万个用户,但是结果是相同的。

从性能的角度来看,什么是最好的方法?为什么

真实的数据库包含大约2000万笔交易,分为10个组和10万个用户。

3 个答案:

答案 0 :(得分:0)

可以请您尝试以下脚本吗?这应该返回与您的查询相同的结果。

  

请测试输出是否与您的查询相同。如果不匹配,请忽略此解决方案。

SELECT E.*,
CASE 
    WHEN (E.UserDetailsId IS NULL AND E.UserDetailsId2 IS NULL) THEN 'N/A'
    ELSE  CONCAT(FirstName, '  ', LastName) 
END AS UserName 
FROM TransactionDetail E
LEFT JOIN UserDetails UD  
    ON (E.UserDetailsId = UD.UserDetailsId) 
    OR (E.UserDetailsId2 = UD.UserDetailsId)
WHERE E.TransactionDetailTypeId = @TypeId

答案 1 :(得分:0)

从性能的角度和您的描述,我希望以下各项具有最佳的性能:

SELECT E.*,
       (CASE WHEN E.UserDetailsId IS NOT NULL
             THEN CONCAT(UD.FirstName, ' ', UD.LastName)
             WHEN E.UserDetailsId2 IS NOT NULL
             THEN CONCAT(UD2.FirstName, ' ', UD2.LastName),
             ELSE 'N/A'
        END) AS UserName
FROM TransactionDetail E LEFT JOIN
     UserDb.dbo.UserDetails UD
     ON UD.UserDetailsId = E.UserDetailsId LEFT JOIN
     UserDb.dbo.UserDetails UD2
     ON UD2.UserDetailsId = E.UserDetailsId2
WHERE E.TransactionDetailTypeId = @TypeId;

然后,您需要在TransactionDetail(TransactionDetailTypeId)UserDetails(UserDetailsId)上建立索引。

OR条件下使用ON可能会有两个不利影响。首先是性能。 OR可能会降低性能。在本示例中,这可以缓解,因为WHERE子句可能只匹配一行。

第二个是,如果同时填充了两个字段,那么您将获得两行-而且您似乎只需要一行作为交易ID。

答案 2 :(得分:0)

另一种尝试的方法:

( SELECT ... 'N/A' ...
    FROM TransactionDetail E 
    WHERE  E.TransactionDetailTypeId = @TypeId
       AND E.UserDetailsId  IS  NULL
       AND E.UserDetailsId2 IS  NULL )
UNION ALL
( SELECT ... UD... ...
    FROM TransactionDetail E JOIN UserDetails UD
    WHERE  E.TransactionDetailTypeId = @TypeId
       AND E.UserDetailsId  IS NOT NULL
       AND E.UserDetailsId2 IS  NULL )
UNION ALL
( SELECT ... UD2... ...
    FROM TransactionDetail E JOIN UserDetails UD2
    WHERE  E.TransactionDetailTypeId = @TypeId
       AND E.UserDetailsId  IS  NULL
       AND E.UserDetailsId2 IS NOT NULL )
UNION ALL
( SELECT ... UD...UD2... ...
    FROM TransactionDetail E JOIN UserDetails UD JOIN UserDetails UD2
    WHERE  E.TransactionDetailTypeId = @TypeId
       AND E.UserDetailsId  IS NOT NULL
       AND E.UserDetailsId2 IS NOT NULL) )

拥有INDEX(TransactionDetailTypeId, UserDetailsId, UserDetailsId2)

可以