Question

I have a query with multiple queries in it that get tied together at the end. I am working through optimizing it, to get it to run faster. I was using 3 queries that created tables and inserted records into them. I looked at my execution plan and saw that one of them was eating up 100% of the cost relative to the batch, so I changed it to the form of ;WITH CTE AS() and that brought it's cost down to 64% of the batch.

Right now I see that the Hash Match (Aggreagate) inside of this query represents 41% of the cost of this query. From the estimated plan it also says that Missing Index (Impact 71.7682): CREATE NONCLUSTERED INDEX.... Is this something that can be done inside of the WITH query?

Here is the part that I am trying to make more efficient

;WITH ERCNT AS (
    SELECT A.MRN
    , A.VISIT_ID
    , A.VISIT_DATE
    , COUNT(B.VISIT_ID) AS VISIT_COUNT

    FROM 
    (
    SELECT MED_REC_NO AS MRN, vst_start_dtime AS VISIT_DATE, PT_NO AS VISIT_ID
    FROM smsdss.BMH_PLM_PtAcct_V
    WHERE
    ((
        Plm_Pt_Acct_Type = 'I'
        AND Adm_Source NOT IN 
            (
            'RP'
            )
        )
        OR pt_type = 'E')
    AND vst_start_dtime >= @SD 
    AND vst_start_dtime < @ED
    )A

    LEFT JOIN
    (
    SELECT MED_REC_NO AS MRN, VST_START_DTIME AS VISIT_DATE, PT_NO AS VISIT_ID
    FROM smsdss.BMH_PLM_PtAcct_V
    WHERE
    ((
        Plm_Pt_Acct_Type = 'I'
        AND Adm_Source NOT IN
            (
            'RP'
            )
        )
        OR pt_type = 'E')
    AND vst_start_dtime >= @SD 
    AND vst_start_dtime < @ED
)B
ON A.MRN = B.MRN
AND A.VISIT_DATE > B.VISIT_DATE
--AND A.VISIT_DATE < B.VISIT_DATE

GROUP BY A.MRN, A.VISIT_ID, A.VISIT_DATE
)

If I need to provide additional information please let me know.

Thank you,

Was it helpful?

Solution

So the problem is the left join between A and B. I assume you cannot create the index suggested by query engine. What about using table variable to store the result of the sub-query and have the index there? You can then use that table in your CTE. Following pseudo-code should give you the idea:

DECLARE @tmp TABLE
(
  MRN ???, VISIT_DATE ???, visit_id ???, PRIMARY KEY(MRN, VISIT_DATE)
)

INSERT INTO @tmp
    SELECT MED_REC_NO AS MRN, vst_start_dtime AS VISIT_DATE, PT_NO AS VISIT_ID
    FROM smsdss.BMH_PLM_PtAcct_V
    WHERE
    ((
        Plm_Pt_Acct_Type = 'I'
        AND Adm_Source NOT IN 
            (
            'RP'
            )
        )
        OR pt_type = 'E')
    AND vst_start_dtime >= @SD 
    AND vst_start_dtime < @ED

;WITH ERCNT AS (
    SELECT A.MRN
    , A.VISIT_ID
    , A.VISIT_DATE
    , COUNT(B.VISIT_ID) AS VISIT_COUNT

FROM @tmp A
LEFT JOIN @tmp B
ON A.MRN = B.MRN
AND A.VISIT_DATE > B.VISIT_DATE
GROUP BY A.MRN, A.VISIT_ID, A.VISIT_DATE
)

OTHER TIPS

Took me a while to understand the difference between (...)A and (...)B. Wouldn't it be more readable to use a correlated subquery like this? => IMHO it might even be more efficient as the amount of data to aggregate is going to be smaller. If you can shortcut Plm_Pt_Acct_Type that would probably make it even a bit faster but I don't have enough info on the tables to know if that would result in the same results .. (probably not I think). There is another possibility to somehow shortcut B.vst_start_dtime, @SD, B.vst_start_dtime, @ED and A.vst_start_dtime in the subquery, but I don't have time to think it through right now =)

PS: having more info on the actual tables (constraints, indexes, rowcount, etc) + a print-screen of the actual execution plan would probably help a lot.

;WITH ERCNT AS (SELECT MRN         = MED_REC_NO, 
                       VISIT_ID    = PT_NO,
                       VISIT_DATE  = vst_start_dtime, 
                       VISIT_COUNT = ( SELECT COUNT(*)
                                         FROM smsdss.BMH_PLM_PtAcct_V B
                                        WHERE -- can we simply assume B.Plm_Pt_Acct_Type = A.Plm_Pt_Acct_Type ??
                                            ((
                                                B.Plm_Pt_Acct_Type = 'I'
                                                AND B.Adm_Source NOT IN
                                                    (
                                                    'RP'
                                                    )
                                                )
                                                OR B.pt_type = 'E')
                                          AND B.vst_start_dtime >= @SD 
                                          AND B.vst_start_dtime < @ED
                                          -- 'join'
                                          AND A.MED_REC_NO = B.MED_REC_NO
                                          AND A.PT_NO = B.PT_NO
                                          AND A.vst_start_dtime > B.vst_start_dtime
                                       )

                FROM smsdss.BMH_PLM_PtAcct_V A
                WHERE
                    ((
                        A.Plm_Pt_Acct_Type = 'I'
                        AND A.Adm_Source NOT IN 
                            (
                            'RP'
                            )
                        )
                        OR A.pt_type = 'E')
                    AND A.vst_start_dtime >= @SD 
                    AND A.vst_start_dtime < @ED
                )
SELECT * FROM ERCNT
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top