使用Union Select的SQL查询优化

时间:2016-01-16 10:59:48

标签: sql sql-server sql-server-2008 query-optimization query-performance

我有这个查询,它返回570行,但运行2m 35s。在SQL中,查询执行,但在我的解决方案中,它会给出超时。我怎样才能将其优化为在1m以下运行,优先于30s。

SELECT  [Region] = Region.FirstName,
        [Patient] = Patient.Name,
        [PatientStatus] = AccountRating.Name,
        [MedicalAid] = AccountType.Name,
        [QuoteAmount] = (   SELECT TOP 1 A.Response
                            FROM dbo.Questionnaire Q
                            JOIN dbo.QuestionnaireDefinition QRD
                                ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
                                AND QRD.Name = 'Internal Admin'
                            LEFT JOIN QuestionDefinition QD
                                ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
                                AND QD.QuestionDefinitionID = 5966
                            LEFT OUTER JOIN Answer A
                                ON A.QuestionnaireID = Q.QuestionnaireID
                                AND A.QuestionDefinitionID = QD.QuestionDefinitionID
                            WHERE Q.IsActive = 1
                            AND Q.SubscriberID = 240
                            AND Q.AccountID = Patient.AccountID
                        ),
        [InvoiceAmount] =   (   SELECT TOP 1 A.Response
                                FROM dbo.Questionnaire Q
                                JOIN dbo.QuestionnaireDefinition QRD
                                    ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
                                    AND QRD.Name = 'Internal Admin'
                                LEFT JOIN QuestionDefinition QD
                                    ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
                                    AND QD.QuestionDefinitionID = 5969
                                LEFT OUTER JOIN Answer A
                                    ON A.QuestionnaireID = Q.QuestionnaireID
                                    AND A.QuestionDefinitionID = QD.QuestionDefinitionID
                                WHERE Q.IsActive = 1
                                AND Q.SubscriberID = 240
                                AND Q.AccountID = Patient.AccountID
                            ),
        [DateSubmitted] =   (   SELECT TOP 1 A.Response
                                FROM dbo.Questionnaire Q
                                JOIN dbo.QuestionnaireDefinition QRD
                                    ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
                                    AND QRD.Name = 'Internal Admin'
                                LEFT JOIN QuestionDefinition QD
                                    ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
                                    AND QD.QuestionDefinitionID = 5965
                                LEFT OUTER JOIN Answer A
                                    ON A.QuestionnaireID = Q.QuestionnaireID
                                    AND A.QuestionDefinitionID = QD.QuestionDefinitionID
                                WHERE Q.IsActive = 1
                                AND Q.SubscriberID = 240
                                AND Q.AccountID = Patient.AccountID
                            ),
        [DateApprovedDeclined] =    (   SELECT TOP 1 A.Response
                                        FROM dbo.Questionnaire Q
                                        JOIN dbo.QuestionnaireDefinition QRD
                                            ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
                                            AND QRD.Name = 'Internal Admin'
                                        LEFT JOIN QuestionDefinition QD
                                            ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
                                            AND QD.QuestionDefinitionID = 5968
                                        LEFT OUTER JOIN Answer A
                                            ON A.QuestionnaireID = Q.QuestionnaireID
                                            AND A.QuestionDefinitionID = QD.QuestionDefinitionID
                                        WHERE Q.IsActive = 1
                                        AND Q.SubscriberID = 240
                                        AND Q.AccountID = Patient.AccountID
                                    ),
        [IntAdmFormCreatedDate]= Q.DateCreated,
        [HasAdminForm] = 'Yes',
        [CreatedByUser] = PatientCreatedBy.Name
FROM dbo.Account AS Patient
JOIN dbo.AccountRating
    ON Patient.AccountRatingID = AccountRating.AccountRatingID
JOIN dbo.AccountType
    ON Patient.AccountTypeID = AccountType.AccountTypeID
JOIN dbo.[User] Region
    ON Patient.UserID = Region.UserID
JOIN dbo.[User] PatientCreatedBy
    ON Patient.CreatedBy = PatientCreatedBy.UserID
JOIN dbo.Questionnaire Q
    ON Patient.AccountID = Q.AccountID

WHERE Patient.SubscriberID = 240
    AND (Q.DateCreated < DATEADD(D, 26, DATEADD(MONTH, DATEDIFF(MONTH, CONVERT(DATETIME, '1900-01-01 00:00:00', 102), GETDATE()), CONVERT(DATETIME, '1900-01-01 00:00:00', 102))))
    AND Q.QuestionnaireDefinitionID = 235
    AND Q.IsActive = 1
    AND Region.FirstName <> 'Rubbish'

UNION SELECT    [Region] = Region.FirstName, 
                [Patient] = Patient.Name, 
                [PatientStatus] = AccountRating.Name, 
                [MedicalAid] = AccountType.Name, 
                [QuoteAmount] = '0', 
                [InvoiceAmount] = '0', 
                [DateSubmitted] = '', 
                [DateApprovedDeclined] = '',
                [IntAdmFormCreatedDate] = '',
                [HasAdminForm] = 'No',
                [CreatedByUser] = PatientCreatedBy.Name 
FROM dbo.Account AS Patient 
JOIN dbo.AccountRating
    ON Patient.AccountRatingID = AccountRating.AccountRatingID 
JOIN dbo.AccountType
    ON Patient.AccountTypeID = AccountType.AccountTypeID 
JOIN dbo.[User] AS Region
    ON Patient.UserID = Region.UserID 
JOIN dbo.[User] AS PatientCreatedBy
    ON Patient.CreatedBy = PatientCreatedBy.UserID
WHERE NOT EXISTS(   SELECT * 
                    FROM Questionnaire AS Q 
                    WHERE Patient.AccountID = Q.AccountID 
                    AND Q.QuestionnaireDefinitionID = 235
                    AND Patient.SubscriberID = 240
                    AND Q.SubscriberID = 240
                )
    AND Patient.SubscriberID = 240
    AND Patient.DateCreated < DATEADD(D, 26, DATEADD(MONTH, DATEDIFF(MONTH, CONVERT(DATETIME, '1900-01-01 00:00:00', 102), GETDATE()), CONVERT(DATETIME, '1900-01-01 00:00:00', 102)))
    AND Region.FirstName <> 'Rubbish'

这是我尝试的另一个版本的查询,但同时运行。

SELECT  [Region] = Region.FirstName,
        [Patient] = Patient.Name,
        [PatientStatus] = AccountRating.Name,
        [MedicalAid] = AccountType.Name,
        [QuoteAmount] = Q1.Response,
        [InvoiceAmount] = Q2.Response,
        [DateSubmitted] = Q3.Response,
        [DateApprovedDeclined] = Q4.Response,
        [IntAdmFormCreatedDate]= Q.DateCreated,
        [HasAdminForm] = 'Yes',
        [CreatedByUser] = PatientCreatedBy.Name
FROM dbo.Account AS Patient
JOIN dbo.AccountRating
    ON Patient.AccountRatingID = AccountRating.AccountRatingID
JOIN dbo.AccountType
    ON Patient.AccountTypeID = AccountType.AccountTypeID
JOIN dbo.[User] Region
    ON Patient.UserID = Region.UserID
JOIN dbo.[User] PatientCreatedBy
    ON Patient.CreatedBy = PatientCreatedBy.UserID
JOIN dbo.Questionnaire Q
    ON Patient.AccountID = Q.AccountID
OUTER APPLY
(
    SELECT TOP 1    Q.AccountID,
            A.Response
    FROM dbo.Questionnaire Q
    JOIN dbo.QuestionnaireDefinition QRD
        ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
        AND QRD.Name = 'Internal Admin'
    LEFT JOIN QuestionDefinition QD
        ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
        AND QD.QuestionDefinitionID = 5966
    LEFT OUTER JOIN Answer A
        ON A.QuestionnaireID = Q.QuestionnaireID
        AND A.QuestionDefinitionID = QD.QuestionDefinitionID
    WHERE Q.IsActive = 1
    Q.SubscriberID = 240
    AND Q.AccountID = Patient.AccountID
) Q1
OUTER APPLY
(
    SELECT TOP 1    Q.AccountID,
                    A.Response
    FROM dbo.Questionnaire Q
    JOIN dbo.QuestionnaireDefinition QRD
        ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
        AND QRD.Name = 'Internal Admin'
    LEFT JOIN QuestionDefinition QD
        ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
        AND QD.QuestionDefinitionID = 5969
    LEFT OUTER JOIN Answer A
        ON A.QuestionnaireID = Q.QuestionnaireID
        AND A.QuestionDefinitionID = QD.QuestionDefinitionID
    WHERE Q.IsActive = 1
    AND Q.AccountID = Patient.AccountID
) Q2
OUTER APPLY
(
    SELECT TOP 1    Q.AccountID,
            A.Response
    FROM dbo.Questionnaire Q
    JOIN dbo.QuestionnaireDefinition QRD
        ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
        AND QRD.Name = 'Internal Admin'
    LEFT JOIN QuestionDefinition QD
        ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
        AND QD.QuestionDefinitionID = 5965
    LEFT OUTER JOIN Answer A
        ON A.QuestionnaireID = Q.QuestionnaireID
        AND A.QuestionDefinitionID = QD.QuestionDefinitionID
    WHERE Q.IsActive = 1
    AND Q.AccountID = Patient.AccountID
) Q3
OUTER APPLY
(
    SELECT TOP 1    Q.AccountID,
                    A.Response
    FROM dbo.Questionnaire Q
    JOIN dbo.QuestionnaireDefinition QRD
        ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
        AND QRD.Name = 'Internal Admin'
    LEFT JOIN QuestionDefinition QD
        ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
        AND QD.QuestionDefinitionID = 5968
    LEFT OUTER JOIN Answer A
        ON A.QuestionnaireID = Q.QuestionnaireID
        AND A.QuestionDefinitionID = QD.QuestionDefinitionID
    WHERE Q.IsActive = 1
    AND Q.AccountID = Patient.AccountID
) Q4
WHERE Patient.SubscriberID = 240
    AND (Q.DateCreated < DATEADD(D, 26, DATEADD(MONTH, DATEDIFF(MONTH, CONVERT(DATETIME, '1900-01-01 00:00:00', 102), GETDATE()), CONVERT(DATETIME, '1900-01-01 00:00:00', 102))))
    AND Q.QuestionnaireDefinitionID = 235
    AND Q.IsActive = 1
    AND Region.FirstName <> 'Rubbish'

UNION SELECT    [Region] = Region.FirstName, 
                [Patient] = Patient.Name, 
                [PatientStatus] = AccountRating.Name, 
                [MedicalAid] = AccountType.Name, 
                [QuoteAmount] = '0', 
                [InvoiceAmount] = '0', 
                [DateSubmitted] = '', 
                [DateApprovedDeclined] = '',
                [IntAdmFormCreatedDate] = '',
                [HasAdminForm] = 'No',
                [CreatedByUser] = PatientCreatedBy.Name 
FROM dbo.Account AS Patient 
JOIN dbo.AccountRating
    ON Patient.AccountRatingID = AccountRating.AccountRatingID 
JOIN dbo.AccountType
    ON Patient.AccountTypeID = AccountType.AccountTypeID 
JOIN dbo.[User] AS Region
    ON Patient.UserID = Region.UserID 
JOIN dbo.[User] AS PatientCreatedBy
    ON Patient.CreatedBy = PatientCreatedBy.UserID
WHERE NOT EXISTS(   SELECT * 
                    FROM Questionnaire AS Q 
                    WHERE Patient.AccountID = Q.AccountID 
                    AND Q.QuestionnaireDefinitionID = 235
                    AND Patient.SubscriberID = 240
                    AND Q.SubscriberID = 240
                )
    AND Patient.SubscriberID = 240
    AND Patient.DateCreated < DATEADD(D, 26, DATEADD(MONTH, DATEDIFF(MONTH, CONVERT(DATETIME, '1900-01-01 00:00:00', 102), GETDATE()), CONVERT(DATETIME, '1900-01-01 00:00:00', 102)))
    AND Region.FirstName <> 'Rubbish'

1 个答案:

答案 0 :(得分:2)

您的标量子查询都共享相同的连接,只是QD.QuestionDefinitionID不同。

您可以使用单个派生表重写这4个TOP并改为加入它:

...
LEFT JOIN
 (
   SELECT 
       Q.AccountID,
       MAX(CASE WHEN QD.QuestionDefinitionID = 5966 THEN A.Response END) AS [DateSubmitted]
       MAX(CASE WHEN QD.QuestionDefinitionID = 5968 THEN A.Response END) AS [DateApprovedDeclined]
       ...
   FROM dbo.Questionnaire Q
   JOIN dbo.QuestionnaireDefinition QRD
       ON QRD.QuestionnaireDefinitionID = Q.QuestionnaireDefinitionID
       AND QRD.NAME = 'Internal Admin'
   LEFT JOIN QuestionDefinition QD
       ON Q.QuestionnaireDefinitionID = QD.QuestionnaireDefinitionID
   LEFT OUTER JOIN Answer A
       ON A.QuestionnaireID = Q.QuestionnaireID
       AND A.QuestionDefinitionID = QD.QuestionDefinitionID
   WHERE Q.IsActive = 1
   AND Q.SubscriberID = 240
   GROUP BY Q.AccountID
 ) AS Q 
ON Q.AccountID = Patient.AccountID

我使用MAX是因为你的子查询中没有ORDER BY,所以确切的值要么无关紧要,要么每个值只有一行。