Execution Plan Help. Enormous Increase in row count in plan

  • Hello All,

    I have been struggling with this plan all morning. I have attempted different indexes. Statistics are up to date. But I keep getting a query plan thats increasing from 1 million rows to a astronomical amount. The table PatientProfile has several left joined look up tables. I am struggling to fix this issue and in some cases adding a index seemed to make it worse.

    Any help appreciated.

    Attached is the execution plan.

    ***SQL born on date Spring 2013:-)

  • UPDATE

    I added a index on the table "List" DatabaseKey,MedlistsID and got a significant improvement. I still have a issue and have narrowed it down to a single join with the table "Language" that I'm still trying to figure out.

    Attached is the new query plan

    ***SQL born on date Spring 2013:-)

  • Can you post the code?

  • And maybe the DDL for the tables including indexes?

  • Here is the query

    SELECT DISTINCT

    Patientsourceid = Pp.Patientprofileid

    , Alternateid = Pp.Patientid

    , Pp.Pid

    , Databaseid = Db.Databaseid

    , Patientstatus = CASE

    WHEN Pp.Pstatus = 'A' THEN 'Active'

    WHEN Pp.Pstatus = 'I' THEN 'Inactive'

    WHEN Pp.Pstatus = 'X' THEN 'Deceased'

    WHEN Pp.Pstatus = 'O' THEN 'Obsolete'

    ELSE 'Unknown'

    END

    , Patientname = ISNULL(Pp.First, '')+' '+ISNULL(Pp.Middle, '')+' '+ISNULL(Pp.Last, '')+' '+ISNULL(Pp.Suffix, '')

    , Firstname = ISNULL(Pp.First, 'N/A')

    , Lastname = ISNULL(Pp.Last, 'N/A')

    , Middlename = ISNULL(Pp.Middle, 'N/A')

    , Suffix = ISNULL(Pp.Suffix, 'N/A')

    , Birthdate = ISNULL(Pp.Birthdate, '01/01/2099')

    , Gender = CASE

    WHEN Pp.Sex = 'M' THEN 'Male'

    WHEN Pp.Sex = 'F' THEN 'Female'

    ELSE 'Unknown'

    END

    , Ethnicity = CASE

    WHEN Eth.[Description] LIKE 'Hisp%' THEN 'Hispanic or Latino'

    WHEN Eth.[Description] LIKE 'Not%' THEN 'Non-Hispanic or Latino'

    WHEN Eth.[Description] LIKE '%Declined%' THEN 'Declined'

    ELSE 'Unknown'

    END

    , Maritalstatus = ISNULL(Ms.]Description], 'Unknown')

    --, Preferredlanguage = ISNULL(ISNULL(L.Shortdescription, Languagelist.Description), 'Unknown')

    , Employmentstatus = ISNULL(Em.[Description], 'N/A')

    , Occupation = ISNULL(Pp.Empoccup, 'N/A')

    , [Address] = ISNULL(ISNULL(Pp.Address1, '')+' '+ISNULL(Pp.Address2, ''), 'N/A')

    , City = ISNULL(Pp.City, 'N/A')

    , County = ISNULL(Pp.County, 'N/A')

    , [State] = ISNULL(Pp.[State], 'N/A')

    , Zip = ISNULL(Pp.Zip, 'Other')

    , Primaryphone = CASE

    WHEN NULLIF(Pp.Phone1, '') IS NOT NULL THEN '('+SUBSTRING(Pp.Phone1, 1, 3)+') '+SUBSTRING(Pp.Phone1, 4, 3)+'-'+SUBSTRING(Pp.Phone1, 7, 4)

    ELSE 'N/A'

    END

    , EmailAddress = ISNULL(Pp.Emailaddress, 'N/A')

    --, Primarycareprovider = ISNULL(Pc.Listname, 'N/A')

    --, Preferredcareprovider = ISNULL(Prf.Listname, 'N/A')

    --, Primaryinsurancecarrier = ISNULL(Ic.Listname, 'N/A')

    --, Facility = ISNULL(Fac.Listname, 'No Facility Assigned')

    ----, Advanceddirectives = ISNULL(Ad.Description, 'None')

    --, Legalguardian = ISNULL(Guard.Description, 'None')

    -- , Changetrackingid = CHECKSUM(Db.Databaseid, Pp.Patientid, Pp.Pstatus, Pp.First, Pp.Last, Pp.Birthdate, Pp.Sex, Eth.Description, Ms.Description, ISNULL((ISNULL(L.Shortdescription, Languagelist.Description))), 'Unknown'), Pp.Address1, Pp.City, Pp.County, Pp.State, Pp.Zip, Pp.Phone1, Pp.Emailaddress, Pc.Listname, Prf.Listname, Fac.Listname )---, Ad.Description, Guard.Description, Pp.Pid)

    FROM

    Patientprofile Pp

    INNER JOIN Visanalyticshouse.Dimension.[Database] Db ON Db.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Eth ON Pp.Ethnicitymid = Eth.Medlistsid AND Eth.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Ms ON Ms.Medlistsid = Pp.Maritalstatusmid AND Ms.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Em ON Em.Medlistsid = Pp.Empstatusmid AND Em.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Languagelist ON Languagelist.Medlistsid = Pp.Preflanguagemid AND Languagelist.Databasekey = Pp.Databasekey

    -- LEFT JOIN [Language] L ON Pp.Languageid = L.Languageid AND L.Databasekey = Pp.Databasekey

    -- LEFT JOIN Patientinsurance pi ON Pi.Databasekey = Pp.Databasekey AND Pi.Patientprofileid = Pp.Patientprofileid AND Pi.Orderforclaims = 1

    --LEFT JOIN Insurancecarriers Ic ON Ic.Insurancecarriersid = Pi.Insurancecarriersid AND Ic.Databasekey = Pp.Databasekey

    --LEFT JOIN Doctorfacility Pc ON Pc.Doctorfacilityid = Pp.Primarycaredoctorid AND Pc.Databasekey = Pp.Databasekey

    --LEFT JOIN Doctorfacility Prf ON Prf.Doctorfacilityid = Pp.Doctorid AND Prf.Databasekey = Pp.Databasekey

    --LEFT JOIN Doctorfacility Fac ON Fac.Doctorfacilityid = Pp.Facilityid AND Fac.Databasekey = Pp.Databasekey

    -- LEFT JOIN Directiv Ad ON Ad.Pid = Pp.Pid AND Ad.Databasekey = Pp.Databasekey AND Ad.Description IN('Do not resuscitate', 'No heroic measures', 'No electrical cardioversion', 'No artificial life support', 'No artificial ventilatory support')

    -- LEFT JOIN Patientrelationship Pr ON Pr.Patientprofileid = Pp.Patientprofileid AND Pr.Databasekey = Pp.Databasekey AND Pr.Type = 5

    -- LEFT JOIN Lists Guard ON Guard.Medlistsid = Pr.Relationshiptypemid AND Guard.Databasekey = Pr.Databasekey;

    ***SQL born on date Spring 2013:-)

  • When I uncomment Language table on the join I get the correct estimate of a little over 1 million rows, however if I then uncomment this "Preferredlanguage = ISNULL(ISNULL(L.Shortdescription, Languagelist.Description), 'Unknown')" in the select it jumps to 3.8 million rows in the execution plan.

    The current index on the Language table is

    CREATE NONCLUSTERED INDEX [IX_Language_DatabasKey_LanguageID] ON [dbo].[Language]

    (

    [DatabaseKey] ASC,

    [LanguageId] ASC

    )

    ***SQL born on date Spring 2013:-)

  • Is it possible that you could post the actual execution plan instead of the estimated plan? That will tell us much more. What you posted may not be the plan that is actually being used.

    Looking at your query (and not having any DDL or sample data) I see that you are doing 4 LEFT joins to your Lists table; in some cases, for a single value. I suspect that you could find a way to reduce this to a single join. In each case the self join is being performed using hash match; each case with a high estimated cost. I bet you can really speed things up if you can get rid of those.

    LEFT JOIN Lists Eth ON Pp.Ethnicitymid = Eth.Medlistsid AND Eth.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Ms ON Ms.Medlistsid = Pp.Maritalstatusmid AND Ms.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Em ON Em.Medlistsid = Pp.Empstatusmid AND Em.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Languagelist ON Languagelist.Medlistsid = Pp.Preflanguagemid AND Languagelist.Databasekey = Pp.Databasekey

    "I cant stress enough the importance of switching from a sequential files mindset to set-based thinking. After you make the switch, you can spend your time tuning and optimizing your queries instead of maintaining lengthy, poor-performing code."

    -- Itzik Ben-Gan 2001

  • Could we see the DDL including indexes for the tables?

  • Alan.B (9/30/2016)


    Is it possible that you could post the actual execution plan instead of the estimated plan? That will tell us much more. What you posted may not be the plan that is actually being used.

    Looking at your query (and not having any DDL or sample data) I see that you are doing 4 LEFT joins to your Lists table; in some cases, for a single value. I suspect that you could find a way to reduce this to a single join. In each case the self join is being performed using hash match; each case with a high estimated cost. I bet you can really speed things up if you can get rid of those.

    LEFT JOIN Lists Eth ON Pp.Ethnicitymid = Eth.Medlistsid AND Eth.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Ms ON Ms.Medlistsid = Pp.Maritalstatusmid AND Ms.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Em ON Em.Medlistsid = Pp.Empstatusmid AND Em.Databasekey = Pp.Databasekey

    LEFT JOIN Lists Languagelist ON Languagelist.Medlistsid = Pp.Preflanguagemid AND Languagelist.Databasekey = Pp.Databasekey

    Looks like Lists is a super lookup table, one lookup table to control them all. We have a table like that here.

  • Thats absolutely correct Lynn, I'm not a fan of it but I have no choice as its a source Production table.

    I messaged you both the information you asked for.

    ***SQL born on date Spring 2013:-)

  • Any reason there aren't any primary keys on any of the tables? For instance, this table: Patientprofile?

  • I should have said this, my appologies. This is a Data Warehouse Enviroment. Those heaps are staging/landing tables. We do not use SSIS against my judgement so this code is actually a Dimension Build from those source staging tables. We do incremental loads but sometimes do a full pull. I can add a Clustered Index if you think it would help and just drop it on full pulls.

    ***SQL born on date Spring 2013:-)

  • At this point I was just wondering, no recommendations yet.

  • I can't see any of the indexes, but perhaps you can combine the Lists lookups as below.

    Also, you'll probably get best performance by clustering the Lists table by ( Databasekey, Medlistsid ) if it's not already.

    SELECT DISTINCT

    ...

    , Lall.Ethnicity

    , Lall.Maritalstatus

    , Lall.Preferredlanguage

    , Lall.Employmentstatus

    , Occupation = ISNULL(Pp.Empoccup, 'N/A')

    ...

    FROM

    Patientprofile Pp

    INNER JOIN Visanalyticshouse.Dimension.[Database] Db ON Db.Databasekey = Pp.Databasekey

    OUTER APPLY (

    SELECT

    ISNULL(MAX(CASE WHEN L.Medlistsid = Pp.Ethnicitymid

    THEN CASE

    WHEN L.Description LIKE 'Hisp%' THEN 'Hispanic or Latino'

    WHEN L.Description LIKE 'Not%' THEN 'Non-Hispanic or Latino'

    WHEN L.Description LIKE '%Declined%' THEN 'Declined'

    ELSE 'Unknown'

    END END), 'Unknown') AS Ethnicity,

    ISNULL(MAX(CASE WHEN L.Medlistsid = Pp.Maritalstatusmid,

    THEN L.Description

    END), 'Unknown') AS Maritalstatus,

    --add similar code for: Employmentstatus and Preferredlanguage

    FROM Lists L

    WHERE L.Databasekey = Pp.Databasekey AND

    L.Medlistsid IN ( Pp.Ethnicitymid, Pp.Maritalstatusmid, Pp.Empstatusmid, Pp.Preflanguagemid )

    ) AS Lall

    LEFT JOIN [Language] L ON Pp.Languageid = L.Languageid AND L.Databasekey = Pp.Databasekey

    ...

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • Is there one column or set of columns in PatientProfile that uniquely identifies each row of data?

    If so, which column or columns?

Viewing 15 posts - 1 through 15 (of 27 total)

You must be logged in to reply to this topic. Login to reply