poor performing report query against table without a PK

  • From the plan:
    There is a huge difference in the estimated and actual number of rows. Have you checked the statistics update date and rows and sampled are same or any skew.
    Your query retrieving a lot of column, the CI is not having all columns.

    Muthukkumaran Kaliyamoorthy
    https://www.sqlserverblogforum.com/

  • Create this index and check out the plan. I'd expect to see a seek for the date and residual predicate for the remaining filter columns, then a key lookup to collect the remaining columns referenced by the query.

    CREATE INDEX ix_Stuff ON [dbo].[QR_Device_Trade_In_Master_2016onward] (ImportFileDate) INCLUDE (BAN, BulkID, Serial_Number, Offer_Generate_Date)

     I think your WHERE clause is still incorrect, try this:

    WHERE (
     BAN = @LOC_BAN
       OR BulkID = @LOC_BulkId
       OR Serial_Number= @LOC_IMEI
       OR ([Offer_Generate_Date] >= @LOC_STARTOFFER AND [Offer_Generate_Date] <= @LOC_ENDOFFER)
     )
     AND ImportFileDate > getdate() - 180

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • you didn't supply us with the indexes on the table - as it seems you generated the script through SSMS I would advise you to set your scripting options to always generate the missing bits - by default it will not script indexes, pk's, compression options and other rather important things.

    I think the following may improve performance - but does require the correct indexes in place.
    It also assumes that the where clause is correctly set - if not you will need to get it right and only then look at what the indexes should be.
    for the sql given on the explain plan file the following indexes would probably be the required ones

    create nonclustered index BAN on QR_Device_Trade_In_Master_2016onward
    (BAN
    )

    create nonclustered index BulkID on QR_Device_Trade_In_Master_2016onward
    (BulkID
    )

    create nonclustered index Serial_Number on QR_Device_Trade_In_Master_2016onward
    (Serial_Number
    )

    create nonclustered index ImportFileDate_Offer_Generate_Date on QR_Device_Trade_In_Master_2016onward
    (ImportFileDate
    ,Offer_Generate_Date
    )

    Note that option ANSI_NULLS being set ON or OFF will affect how this (and the original one) query executes.

    optionally and if that is indeed the intention each of the where clause should really be
    where @variable is not null and column = @variable

    I've also used select * on the unions - this was just to make it easier to read here - should not be used, and you should instead list all required columns


    ;with base
    as
    (select *
    from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    where BAN = @Loc_Ban

    union all

    select *
    from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    where BulkID = @Loc_BulkId

    union all

    select *
    from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    where Serial_Number = @Loc_Imei

    union all

    select *
    from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    where ([Offer_Generate_Date] >= @Loc_StartOffer
    and [Offer_Generate_Date] <= @Loc_EndOffer)
    and ImportFileDate > getdate() - 180
    )
    select qr.[Offer_ID]
      , qr.[Offer_Generate_Date]
      , qr.[Offer_Update_Date]
      , qr.[Manufacturer]
      , qr.[model]
      , qr.[Serial_Number]
      , qr.[Application_User_ID]
      , qr.[Application_ID]
      , qr.[device_Evaluation_Date]
      , qr.[Store_ID]
      , qr.[BAN]
      , qr.[Subscriber_No]
      , qr.[Offer_Amount]
      , qr.[RMA_Number]
      , qr.[Offer_Status]
      , qr.[Rejection_Reason]
      , qr.[RMA_Status]
      , qr.[Settlement_Amount]
      , qr.[Eligibility_Status]
      , qr.[Eligibility_Reason]
      , qr.[Adjustment_Reason]
      , qr.[Bill_Status]
      , qr.[Channel_ID]
      , qr.[Credit_Issue_Date]
      , qr.[Program_ID]
      , qr.[BulkID]
       --,QP.MARKET_ASSESSED_AMOUNT as [Fair Market Value]
       --,QP.PRM_NAME AS Promo
      , qr.Assurant_Manufacturer as [assurant manufacturer received]
      , qr.Assurant_Model as [assurant model received]
    --,COALESCE(Q1.Answer_Name,'N/A') AS [FMiP OFF]
    --,COALESCE(Q6.Answer_Name,'N/A') AS [AntiTheft OFF]
    --,COALESCE(Q2.Answer_Name,'N/A') AS [Liquid Damage]
    --,COALESCE(Q3.Answer_Name,'N/A') AS [Promo Accepted]
    --,COALESCE(Q4.Answer_Name,'N/A') AS [LCD Acceptable]
    --,COALESCE(Q5.Answer_Name,'N/A') AS [Powers On]
    from base qr
    --LEFT JOIN ODS.[dbo].[QR_DR_TradeIn_Promo] QP ON QR.Offer_ID = QP.Offer_ID
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q1 ON QR.Offer_ID = Q1.Offer_ID AND Q1.Question_Name = 'Find My Iphone'--
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q2 ON QR.Offer_ID = Q2.Offer_ID AND Q2.Question_Name = 'Liquid Damage'
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q3 ON QR.Offer_ID = Q3.Offer_ID AND Q3.Question_Name = 'ATLANTIS_PROMO'
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q4 ON QR.Offer_ID = Q4.Offer_ID AND Q4.Question_Name = 'LCD Issue'
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q5 ON QR.Offer_ID = Q5.Offer_ID AND Q5.Question_Name = 'Powers On'
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q6 ON QR.Offer_ID = Q6.Offer_ID AND Q6.Question_Name = 'Anti Theft Disabled'
    where BAN = @Loc_Ban
      or BulkID = @Loc_BulkId
      or Serial_Number = @Loc_Imei
      or ([Offer_Generate_Date] >= @Loc_StartOffer
      and [Offer_Generate_Date] <= @Loc_EndOffer)
      and ImportFileDate > getdate() - 180

  • Tiny nit. Take away the calculation. Make it before in a local variable. It might lead to different row calculations. You are getting a VERY large disparity in estimated versus actual suggesting that your stats may be out of date. However, it's more likely it's all the OR calculations leading to the optimizer effectively throwing up it's hands. I like the suggestion earlier of using UNION ALL. Otherwise, with all the individual indexes, what you're trying to achieve is index intersection. It's a thing, but it's very rare and hard to get. I have an example of it in my book, but that represents hours and hours of work to try to get the perfect set of indexes to intersect. Chances of doing that in the wild are reduced, pretty radically.

    Breaking down the query into a set of UNION ALL with individual WHERE clauses gives the optimizer more choices in satisfying the query. Instead of combining everything in one statement, each individual statement can filter on those discrete indexes best suited to it. Another option to consider is that of the 32 million rows in the table, how many will be eliminated just based on the ImportFileDate column? Maybe load those into a temp table and then filter based on the other columns. One query and one WHERE clause can be the preferred mechanism, but sometimes divide and conquer also works.

    Even tinier nit, consistency when writing your code will serve you extremely well. Add the table owner to all columns as you write the query, even though only one table is being referenced here. That will not help performance of the query, but it will help your performance and others down the road as you make the code easier to read. Again, teeny-tiny nit.

    "The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood"
    - Theodore Roosevelt

    Author of:
    SQL Server Execution Plans
    SQL Server Query Performance Tuning

  • Declare you variables, and populate them:
    DECLARE
     @BULKID    varchar(50) = 5006,
     @BAN   varchar(50) = null,-- '955932237',
     @FROM_DATE  date = NULL,
     @TO_DATE  date = NULL,
     @IMEI    varchar(100) = NULL

    Create a temporary table:
    IF OBJECT_ID('tempdb..[#Assurant Manufacturer Received]','U') IS NOT NULL BEGIN
      PRINT 'DROP TABLE [#Assurant Manufacturer Received]'
      DROP TABLE [#Assurant Manufacturer Received]
    END
    CREATE TABLE [#Assurant Manufacturer Received]
    (
      [Offer_ID] [varchar](500) NULL,
      [Offer_Generate_Date] [datetime] NULL,
      [Offer_Update_Date] [datetime] NULL,
      [Manufacturer] [varchar](300) NOT NULL,
      [Model] [varchar](300) NOT NULL,
      [Serial_Number] [varchar](100) NOT NULL,
      [Application_User_ID] [varchar](500) NULL,
      [Application_ID] [varchar](500) NULL,
      [device_Evaluation_Date] [datetime] NULL,
      [Store_ID] [varchar](100) NULL,
      [BAN] [numeric](9, 0) NULL,
      [Subscriber_No] [varchar](20) NULL,
      [Offer_Amount] [numeric](8, 4) NULL,
      [RMA_Number] [varchar](100) NULL,
      [Offer_Status] [varchar](100) NULL,
      [Rejection_Reason] [varchar](300) NULL,
      [RMA_Status] [varchar](100) NULL,
      [Settlement_Amount] [numeric](8, 4) NULL,
      [Eligibility_Status] [varchar](100) NULL,
      [Eligibility_Reason] [varchar](1000) NULL,
      [Bill_Status] [varchar](1) NULL,
      [Channel_ID] [varchar](500) NULL,
      [Assurant_Manufacturer] [varchar](300) NULL,
      [Assurant_Model] [varchar](300) NULL
    )

    Then select only rows from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] into it using unions:
    INSERT INTO [#Assurant Manufacturer Received]
    (
      [Offer_ID],
      [Offer_Generate_Date],
      [Offer_Update_Date],
      [Manufacturer],
      [Model],
      [Serial_Number],
      [Application_User_ID],
      [Application_ID],
      [device_Evaluation_Date],
      [Store_ID],
      [BAN],
      [Subscriber_No],
      [Offer_Amount],
      [RMA_Number],
      [Offer_Status],
      [Rejection_Reason],
      [RMA_Status],
      [Settlement_Amount],
      [Eligibility_Status],
      [Eligibility_Reason],
      [Bill_Status],
      [Channel_ID],
      [Assurant_Manufacturer],
      [Assurant_Model]
    )
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
    FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    WHERE BAN = @BAN
    UNION
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
    FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    WHERE BulkID = @BULKID
    UNION
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
    FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    WHERE Serial_Number = @IMEI
    UNION
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
    FROM [#Assurant Manufacturer Received] QR
    WHERE [Offer_Generate_Date] BETWEEN @FROM_DATE AND @TO_DATE

    Then create the rest of your query from the temporary table ([#Assurant Manufacturer Received]):
    SELECT QR.[Offer_ID]
      ,QR.[Offer_Generate_Date]
      ,QR.[Offer_Update_Date]
      ,QR.[Manufacturer]
      ,QR.[Model]
      ,QR.[Serial_Number]
      ,QR.[Application_User_ID]
      ,QR.[Application_ID]
      ,QR.[device_Evaluation_Date]
      ,QR.[Store_ID]
      ,QR.[BAN]
      ,QR.[Subscriber_No]
      ,QR.[Offer_Amount]
      ,QR.[RMA_Number]
      ,QR.[Offer_Status]
      ,QR.[Rejection_Reason]
      ,QR.[RMA_Status]
      ,QR.[Settlement_Amount]
      ,QR.[Eligibility_Status]
      ,QR.[Eligibility_Reason]
      ,QR.[Adjustment_Reason]
      ,QR.[Bill_Status]
      ,QR.[Channel_ID]
      ,QR.[Credit_Issue_Date]
      ,QR.[Program_ID]
      ,QR.[BulkID]
      ,QP.MARKET_ASSESSED_AMOUNT as [Fair Market Value]
      ,QP.PRM_NAME AS Promo
      ,QR.Assurant_Manufacturer as [Assurant Manufacturer Received]
      ,QR.Assurant_Model as [Assurant Model Received]
      ,COALESCE(Q1.Answer_Name,'N/A') AS [FMiP OFF]
      ,COALESCE(Q6.Answer_Name,'N/A') AS [AntiTheft OFF]
      ,COALESCE(Q2.Answer_Name,'N/A') AS [Liquid Damage]
      ,COALESCE(Q3.Answer_Name,'N/A') AS [Promo Accepted]
      ,COALESCE(Q4.Answer_Name,'N/A') AS [LCD Acceptable]
      ,COALESCE(Q5.Answer_Name,'N/A') AS [Powers On]
    FROM [#Assurant Manufacturer Received] QR
    LEFT JOIN ODS.[dbo].[QR_DR_TradeIn_Promo] QP ON QR.Offer_ID = QP.Offer_ID
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q1 ON QR.Offer_ID = Q1.Offer_ID AND Q1.Question_Name = 'Find My Iphone'--
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q2 ON QR.Offer_ID = Q2.Offer_ID AND Q2.Question_Name = 'Liquid Damage'
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q3 ON QR.Offer_ID = Q3.Offer_ID AND Q3.Question_Name = 'ATLANTIS_PROMO'
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q4 ON QR.Offer_ID = Q4.Offer_ID AND Q4.Question_Name = 'LCD Issue'
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q5 ON QR.Offer_ID = Q5.Offer_ID AND Q5.Question_Name = 'Powers On'
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q6 ON QR.Offer_ID = Q6.Offer_ID AND Q6.Question_Name = 'Anti Theft Disabled'

  • ChrisM@Work - Tuesday, November 27, 2018 1:11 AM

    Create this index and check out the plan. I'd expect to see a seek for the date and residual predicate for the remaining filter columns, then a key lookup to collect the remaining columns referenced by the query.

    CREATE INDEX ix_Stuff ON [dbo].[QR_Device_Trade_In_Master_2016onward] (ImportFileDate) INCLUDE (BAN, BulkID, Serial_Number, Offer_Generate_Date)

     I think your WHERE clause is still incorrect, try this:

    WHERE (
     BAN = @LOC_BAN
       OR BulkID = @LOC_BulkId
       OR Serial_Number= @LOC_IMEI
       OR ([Offer_Generate_Date] >= @LOC_STARTOFFER AND [Offer_Generate_Date] <= @LOC_ENDOFFER)
     )
     AND ImportFileDate > getdate() - 180

    If that's the correct WHERE structure -- specifically that you (nearly) always specify an ImportFileDate range, then you need to cluster the table first on ImportFileDate.  Strongly consider adding BulkID or OfferID as key#2 in the clus index, if that combination of columns would always be unique.  That allows you to define the clus key as UNIQUE, which would be beneficial for this table.

    The best, most complete way to improve query speed is to get the best clus index on the table first.  Otherwise, you're going to be constantly having to futz with nonclus indexes and still never getting consistently good query performance.

    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".

  • ScottPletcher - Tuesday, November 27, 2018 10:10 AM

    ChrisM@Work - Tuesday, November 27, 2018 1:11 AM

    Create this index and check out the plan. I'd expect to see a seek for the date and residual predicate for the remaining filter columns, then a key lookup to collect the remaining columns referenced by the query.

    CREATE INDEX ix_Stuff ON [dbo].[QR_Device_Trade_In_Master_2016onward] (ImportFileDate) INCLUDE (BAN, BulkID, Serial_Number, Offer_Generate_Date)

     I think your WHERE clause is still incorrect, try this:

    WHERE (
     BAN = @LOC_BAN
       OR BulkID = @LOC_BulkId
       OR Serial_Number= @LOC_IMEI
       OR ([Offer_Generate_Date] >= @LOC_STARTOFFER AND [Offer_Generate_Date] <= @LOC_ENDOFFER)
     )
     AND ImportFileDate > getdate() - 180

    If that's the correct WHERE structure -- specifically that you (nearly) always specify an ImportFileDate range, then you need to cluster the table first on ImportFileDate.  Strongly consider adding BulkID or OfferID as key#2 in the clus index, if that combination of columns would always be unique.  That allows you to define the clus key as UNIQUE, which would be beneficial for this table.

    The best, most complete way to improve query speed is to get the best clus index on the table first.  Otherwise, you're going to be constantly having to futz with nonclus indexes and still never getting consistently good query performance.

    Where did the additional criteria "AND ImportFileDate > getdate() - 180" come from?

  • Jonathan AC Roberts - Tuesday, November 27, 2018 1:46 PM

    ScottPletcher - Tuesday, November 27, 2018 10:10 AM

    ChrisM@Work - Tuesday, November 27, 2018 1:11 AM

    Create this index and check out the plan. I'd expect to see a seek for the date and residual predicate for the remaining filter columns, then a key lookup to collect the remaining columns referenced by the query.

    CREATE INDEX ix_Stuff ON [dbo].[QR_Device_Trade_In_Master_2016onward] (ImportFileDate) INCLUDE (BAN, BulkID, Serial_Number, Offer_Generate_Date)

     I think your WHERE clause is still incorrect, try this:

    WHERE (
     BAN = @LOC_BAN
       OR BulkID = @LOC_BulkId
       OR Serial_Number= @LOC_IMEI
       OR ([Offer_Generate_Date] >= @LOC_STARTOFFER AND [Offer_Generate_Date] <= @LOC_ENDOFFER)
     )
     AND ImportFileDate > getdate() - 180

    If that's the correct WHERE structure -- specifically that you (nearly) always specify an ImportFileDate range, then you need to cluster the table first on ImportFileDate.  Strongly consider adding BulkID or OfferID as key#2 in the clus index, if that combination of columns would always be unique.  That allows you to define the clus key as UNIQUE, which would be beneficial for this table.

    The best, most complete way to improve query speed is to get the best clus index on the table first.  Otherwise, you're going to be constantly having to futz with nonclus indexes and still never getting consistently good query performance.

    Where did the additional criteria "AND ImportFileDate > getdate() - 180" come from?

    its on the explain plan supplied

  • polkadot - Monday, November 26, 2018 12:39 PM

    Answers to Qs:
    Grant Fritchey: (1) I added parenthesis around Date.  (2) using parameters. Attached query.
    ChrisM: (1) table has 98 columns (2) selectivity of columns will change over time (3) rows returned will be between 5 to 50
    Erik Erikson:  (1) IMEI is mobile. (2) you'll see from DDL that some columns are quite huge and all but one, Bill_Process_Failure_Reason @ varchar(4000) is justified. 
    Jonathan AC Roberts: I don't think I will take UNION route because report query actually has a number of JOINS that I have commented out for sake of addressing bottlenecks one step at a time 

    attached exec plan  /  inserted DDL, and report query.

    DDL


    SET ANSI_NULLS ON
    GO

    SET QUOTED_IDENTIFIER ON
    GO

    SET ANSI_PADDING ON
    GO

    CREATE TABLE [dbo].[QR_Device_Trade_In_Master](


    [Offer_ID] [varchar](500) NULL,


    [Offer_Generate_Date] [datetime] NULL,


    [Offer_Update_Date] [datetime] NULL,


    [Manufacturer] [varchar](300) NOT NULL,


    [Model] [varchar](300) NOT NULL,


    [Serial_Number] [varchar](100) NOT NULL,


    [Serial_Number_Type] [varchar](50) NULL,


    [Application_User_ID] [varchar](500) NULL,


    [Application_ID] [varchar](500) NULL,


    [device_Evaluation_Date] [datetime] NULL,


    [Store_ID] [varchar](100) NULL,


    [Purchase_Device_Sku] [varchar](100) NULL,


    [BAN] [numeric](9, 0) NULL,


    [Subscriber_No] [varchar](20) NULL,


    [Offer_Amount] [numeric](8, 4) NULL,


    [RMA_Number] [varchar](100) NULL,


    [Offer_Expiration_Date] [datetime] NULL,


    [Customer_Email_Address] [varchar](100) NULL,


    [Customer_Phone_Number] [varchar](30) NULL,


    [Offer_Status] [varchar](100) NULL,


    [Rejection_Reason] [varchar](300) NULL,


    [RMA_Status] [varchar](100) NULL,


    [RMA_Expiration_Date] [datetime] NULL,


    [Settlement_Amount] [numeric](8, 4) NULL,


    [Network_Operator] [varchar](100) NOT NULL,


    [Shipping_Label_URL] [varchar](2000) NULL,


    [Eligibility_Status] [varchar](100) NULL,


    [Eligibility_Reason] [varchar](1000) NULL,


    [Is_Customer_Billed] [varchar](1) NULL,


    [Adjustment_Reason] [varchar](2000) NULL,


    [Bill_Status] [varchar](1) NULL,


    [Bill_Process_Failure_Reason] [varchar](4000) NULL,


    [Eligibility_Reason_Code] [varchar](100) NULL,


    [Sender_ID] [varchar](500) NULL,


    [Channel_ID] [varchar](500) NULL,


    [Session_ID] [varchar](500) NULL,


    [Work_Flow_ID] [varchar](500) NULL,


    [Activity_ID] [varchar](500) NULL,


    [Dealer_Code] [varchar](500) NULL,


    [Credit_Issue_Date] [datetime] NULL,


    [Create_Date] [datetime] NOT NULL,


    [Created_By] [varchar](500) NULL,


    [Update_Date] [datetime] NULL,


    [Updated_By] [varchar](500) NULL,


    [Image_Url] [varchar](4000) NULL,


    [Sales_Document_Number] [varchar](100) NULL,


    [Purchase_Order_Number] [varchar](100) NULL,


    [Sap_Channel] [varchar](50) NULL,


    [Sap_Return_Type] [varchar](10) NULL,


    [Sap_Return_Message] [varchar](1000) NULL,


    [Transaction_Type] [varchar](100) NULL,


    [ProcessLogID] [int] NOT NULL,


    [ImportFileDate] [date] NOT NULL,


    [Event_Type] [varchar](100) NULL,


    [Retail_Store_Type] [varchar](50) NULL,


    [Assurant_Model] [varchar](300) NULL,


    [Assurant_Manufacturer] [varchar](300) NULL,


    [Cancel_Reason] [varchar](500) NULL,


    [Program_ID] [varchar](10) NOT NULL,


    [Fulfillment_Ord_Number_Forward] [varchar](30) NULL,


    [EIP_Balance] [numeric](8, 4) NULL,


    [EIP_Plan_ID] [varchar](50) NULL,


    [EIP_Device_ID] [varchar](50) NULL,


    [Claim_Auth_Code] [varchar](50) NULL,


    [Claim_Req] [varchar](2) NULL,


    [Claim_Auth_Date] [date] NULL,


    [Claim_Auth_Available] [varchar](2) NULL,


    [Deductible_Amount] [numeric](8, 4) NULL,


    [Device_Collection_Required] [varchar](2) NULL,


    [Claimed_Device_Collected] [varchar](1) NULL,


    [Jump_TradeIn_Value] [numeric](8, 4) NULL,


    [Claim_Submitted_By] [varchar](100) NULL,


    [TOTAL_DAMAGE_AMOUNT] [numeric](10, 4) NULL,


    [INSURANCE_DEDUCTABLE_AMOUNT] [numeric](10, 4) NULL,


    [DEVICE_SHIPMENT_DATE] [date] NULL,


    [DEVICE_RETURN_EXPIRATION_DATE] [date] NULL,


    [DEVICE_RETURN_DATE] [date] NULL,


    [DEVICE_RETURN_SESSION_ID] [varchar](100) NULL,


    [ORIGINAL_RMA_NUMBER] [varchar](100) NULL,


    [UPDATED_RMA_EXPIRATION_DATE] [date] NULL,


    [Adjustment_Id] [varchar](50) NULL,


    [Tracking_Carrier] [varchar](100) NULL,


    [Tracking_Number] [varchar](50) NULL,


    [Return_Tracking_Number] [varchar](100) NULL,


    [Trade_In_Sub_Status] [varchar](50) NULL,


    [Trade_In_Status] [varchar](50) NULL,


    [Return_Tracking_Carrier] [varchar](100) NULL,


    [Bill_Credit_Balance] [numeric](8, 4) NULL,


    [Device_Received_Date] [date] NULL,


    [Trade_In_Credit_Date] [date] NULL,


    [Credited_Down_Payment] [numeric](8, 4) NULL,


    [Returned_Date] [date] NULL,


    [TRADEIN_INTENT] [varchar](50) NULL,


    [ORDER_LINE_ID] [varchar](50) NULL,


    [BulkID] [varchar](50) NULL


    ) ON [PRIMARY]
    GO

    SET ANSI_PADDING

    OFF

    GO

    Report Query 
    In report query you'll notice I am pulling from table with '
    _2016onward' which is a copy of the table, containing records from year 2016 onward, so as not to interfere with production table while testing new indexes in production.  
    Have commented out the JOINS to focus on primary table


    DECLARE


    @BULKID varchar(50) = 5006,


    @BANvarchar(50) = null,-- '955932237',


    @FROM_DATEdate = NULL,


    @TO_DATEdate = NULL,


    @IMEI varchar(100) = NULL


    SELECT QR.[Offer_ID]


    ,QR.[Offer_Generate_Date]


    ,QR.[Offer_Update_Date]


    ,QR.[Manufacturer]


    ,QR.[Model]


    ,QR.[Serial_Number]


    ,QR.[Application_User_ID]


    ,QR.[Application_ID]


    ,QR.[device_Evaluation_Date]


    ,QR.[Store_ID]


    ,QR.[BAN]


    ,QR.[Subscriber_No]


    ,QR.[Offer_Amount]


    ,QR.[RMA_Number]


    ,QR.[Offer_Status]


    ,QR.[Rejection_Reason]


    ,QR.[RMA_Status]


    ,QR.[Settlement_Amount]


    ,QR.[Eligibility_Status]


    ,QR.[Eligibility_Reason]


    ,QR.[Adjustment_Reason]


    ,QR.[Bill_Status]


    ,QR.[Channel_ID]


    ,QR.[Credit_Issue_Date]


    ,QR.[Program_ID]


    ,QR.[BulkID]


    --,QP.MARKET_ASSESSED_AMOUNT as [Fair Market Value]


    --,QP.PRM_NAME AS Promo


    ,QR.Assurant_Manufacturer as [Assurant Manufacturer Received]


    ,QR.Assurant_Model as [Assurant Model Received]


    --,COALESCE(Q1.Answer_Name,'N/A') AS [FMiP OFF]


    --,COALESCE(Q6.Answer_Name,'N/A') AS [AntiTheft OFF]


    --,COALESCE(Q2.Answer_Name,'N/A') AS [Liquid Damage]


    --,COALESCE(Q3.Answer_Name,'N/A') AS [Promo Accepted]


    --,COALESCE(Q4.Answer_Name,'N/A') AS [LCD Acceptable]


    --,COALESCE(Q5.Answer_Name,'N/A') AS [Powers On]


    FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR


    --LEFT JOIN ODS.[dbo].[QR_DR_TradeIn_Promo] QP ON QR.Offer_ID = QP.Offer_ID


    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q1 ON QR.Offer_ID = Q1.Offer_ID AND Q1.Question_Name = 'Find My Iphone'--


    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q2 ON QR.Offer_ID = Q2.Offer_ID AND Q2.Question_Name = 'Liquid Damage'


    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q3 ON QR.Offer_ID = Q3.Offer_ID AND Q3.Question_Name = 'ATLANTIS_PROMO'


    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q4 ON QR.Offer_ID = Q4.Offer_ID AND Q4.Question_Name = 'LCD Issue'


    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q5 ON QR.Offer_ID = Q5.Offer_ID AND Q5.Question_Name = 'Powers On'


    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q6 ON QR.Offer_ID = Q6.Offer_ID AND Q6.Question_Name = 'Anti Theft Disabled'


    WHERE


    BAN = @BAN


    OR BulkID = @BULKID


    OR Serial_Number= @IMEI


    OR ([Offer_Generate_Date] >= @FROM_DATE AND [Offer_Generate_Date] <= @TO_DATE)


    GO


    It's not your fault... the forum software sucks pretty badly and they're supposedly going to fix it in the near future (of course, they've been saying that for 2 years but whatever). Here's a way to help us help you in the future until they do.

    The code above is horrible to read because of all the white space between each line.  Instead of just doing a copy and paste, do a copy and then paste into NotePad.  That get's rid of a lot of junk white space.  Then copy from NotePad into this forum within the SQL tags you used.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • frederico_fonseca - Tuesday, November 27, 2018 1:51 AM

    you didn't supply us with the indexes on the table - as it seems you generated the script through SSMS I would advise you to set your scripting options to always generate the missing bits - by default it will not script indexes, pk's, compression options and other rather important things.

    I think the following may improve performance - but does require the correct indexes in place.
    It also assumes that the where clause is correctly set - if not you will need to get it right and only then look at what the indexes should be.
    for the sql given on the explain plan file the following indexes would probably be the required ones

    create nonclustered index BAN on QR_Device_Trade_In_Master_2016onward
    (BAN
    )

    create nonclustered index BulkID on QR_Device_Trade_In_Master_2016onward
    (BulkID
    )

    create nonclustered index Serial_Number on QR_Device_Trade_In_Master_2016onward
    (Serial_Number
    )

    create nonclustered index ImportFileDate_Offer_Generate_Date on QR_Device_Trade_In_Master_2016onward
    (ImportFileDate
    ,Offer_Generate_Date
    )

    Note that option ANSI_NULLS being set ON or OFF will affect how this (and the original one) query executes.

    optionally and if that is indeed the intention each of the where clause should really be
    where @variable is not null and column = @variable

    I've also used select * on the unions - this was just to make it easier to read here - should not be used, and you should instead list all required columns


    ;with base
    as
    (select *
    from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    where BAN = @Loc_Ban

    union all

    select *
    from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    where BulkID = @Loc_BulkId

    union all

    select *
    from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    where Serial_Number = @Loc_Imei

    union all

    select *
    from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    where ([Offer_Generate_Date] >= @Loc_StartOffer
    and [Offer_Generate_Date] <= @Loc_EndOffer)
    and ImportFileDate > getdate() - 180
    )
    select qr.[Offer_ID]
      , qr.[Offer_Generate_Date]
      , qr.[Offer_Update_Date]
      , qr.[Manufacturer]
      , qr.[model]
      , qr.[Serial_Number]
      , qr.[Application_User_ID]
      , qr.[Application_ID]
      , qr.[device_Evaluation_Date]
      , qr.[Store_ID]
      , qr.[BAN]
      , qr.[Subscriber_No]
      , qr.[Offer_Amount]
      , qr.[RMA_Number]
      , qr.[Offer_Status]
      , qr.[Rejection_Reason]
      , qr.[RMA_Status]
      , qr.[Settlement_Amount]
      , qr.[Eligibility_Status]
      , qr.[Eligibility_Reason]
      , qr.[Adjustment_Reason]
      , qr.[Bill_Status]
      , qr.[Channel_ID]
      , qr.[Credit_Issue_Date]
      , qr.[Program_ID]
      , qr.[BulkID]
       --,QP.MARKET_ASSESSED_AMOUNT as [Fair Market Value]
       --,QP.PRM_NAME AS Promo
      , qr.Assurant_Manufacturer as [assurant manufacturer received]
      , qr.Assurant_Model as [assurant model received]
    --,COALESCE(Q1.Answer_Name,'N/A') AS [FMiP OFF]
    --,COALESCE(Q6.Answer_Name,'N/A') AS [AntiTheft OFF]
    --,COALESCE(Q2.Answer_Name,'N/A') AS [Liquid Damage]
    --,COALESCE(Q3.Answer_Name,'N/A') AS [Promo Accepted]
    --,COALESCE(Q4.Answer_Name,'N/A') AS [LCD Acceptable]
    --,COALESCE(Q5.Answer_Name,'N/A') AS [Powers On]
    from base qr
    --LEFT JOIN ODS.[dbo].[QR_DR_TradeIn_Promo] QP ON QR.Offer_ID = QP.Offer_ID
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q1 ON QR.Offer_ID = Q1.Offer_ID AND Q1.Question_Name = 'Find My Iphone'--
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q2 ON QR.Offer_ID = Q2.Offer_ID AND Q2.Question_Name = 'Liquid Damage'
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q3 ON QR.Offer_ID = Q3.Offer_ID AND Q3.Question_Name = 'ATLANTIS_PROMO'
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q4 ON QR.Offer_ID = Q4.Offer_ID AND Q4.Question_Name = 'LCD Issue'
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q5 ON QR.Offer_ID = Q5.Offer_ID AND Q5.Question_Name = 'Powers On'
    --LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q6 ON QR.Offer_ID = Q6.Offer_ID AND Q6.Question_Name = 'Anti Theft Disabled'
    where BAN = @Loc_Ban
      or BulkID = @Loc_BulkId
      or Serial_Number = @Loc_Imei
      or ([Offer_Generate_Date] >= @Loc_StartOffer
      and [Offer_Generate_Date] <= @Loc_EndOffer)
      and ImportFileDate > getdate() - 180

    The OP would need to use UNION, they may get duplicate rows if they use UNION ALL .

  • I've updated my last response to cope with the additional criteria on ImportFileDate:
    Declare you variables, and populate them:
    DECLARE
     @BULKID    varchar(50) = 5006,
     @BAN   varchar(50) = null,-- '955932237',
     @FROM_DATE  date = NULL,
     @TO_DATE  date = NULL,
     @IMEI    varchar(100) = NULL

    Create a temporary table:
    IF OBJECT_ID('tempdb..[#Assurant Manufacturer Received]','U') IS NOT NULL BEGIN
      PRINT 'DROP TABLE [#Assurant Manufacturer Received]'
      DROP TABLE [#Assurant Manufacturer Received]
    END
    CREATE TABLE [#Assurant Manufacturer Received]
    (
      [Offer_ID] [varchar](500) NULL,
      [Offer_Generate_Date] [datetime] NULL,
      [Offer_Update_Date] [datetime] NULL,
      [Manufacturer] [varchar](300) NOT NULL,
      [Model] [varchar](300) NOT NULL,
      [Serial_Number] [varchar](100) NOT NULL,
      [Application_User_ID] [varchar](500) NULL,
      [Application_ID] [varchar](500) NULL,
      [device_Evaluation_Date] [datetime] NULL,
      [Store_ID] [varchar](100) NULL,
      [BAN] [numeric](9, 0) NULL,
      [Subscriber_No] [varchar](20) NULL,
      [Offer_Amount] [numeric](8, 4) NULL,
      [RMA_Number] [varchar](100) NULL,
      [Offer_Status] [varchar](100) NULL,
      [Rejection_Reason] [varchar](300) NULL,
      [RMA_Status] [varchar](100) NULL,
      [Settlement_Amount] [numeric](8, 4) NULL,
      [Eligibility_Status] [varchar](100) NULL,
      [Eligibility_Reason] [varchar](1000) NULL,
      [Bill_Status] [varchar](1) NULL,
      [Channel_ID] [varchar](500) NULL,
      [Assurant_Manufacturer] [varchar](300) NULL,
      [Assurant_Model] [varchar](300) NULL
    )

    Then select only rows from DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] into it using unions:
    INSERT INTO [#Assurant Manufacturer Received]
    (
      [Offer_ID],
      [Offer_Generate_Date],
      [Offer_Update_Date],
      [Manufacturer],
      [Model],
      [Serial_Number],
      [Application_User_ID],
      [Application_ID],
      [device_Evaluation_Date],
      [Store_ID],
      [BAN],
      [Subscriber_No],
      [Offer_Amount],
      [RMA_Number],
      [Offer_Status],
      [Rejection_Reason],
      [RMA_Status],
      [Settlement_Amount],
      [Eligibility_Status],
      [Eligibility_Reason],
      [Bill_Status],
      [Channel_ID],
      [Assurant_Manufacturer],
      [Assurant_Model]
    )
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
    FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    WHERE ImportFileDate > getdate() - 180
    AND BAN = @BAN
    UNION
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
    FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    WHERE ImportFileDate > getdate() - 180
    AND BulkID = @BULKID
    UNION 
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
    FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    WHERE ImportFileDate > getdate() - 180
    AND Serial_Number = @IMEI
    UNION
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
    FROM [#Assurant Manufacturer Received] QR
    WHERE ImportFileDate > getdate() - 180
    AND [Offer_Generate_Date] BETWEEN @FROM_DATE AND @TO_DATE

    Then create the rest of your query from the temporary table ([#Assurant Manufacturer Received]):
    SELECT QR.[Offer_ID] 
      ,QR.[Offer_Generate_Date] 
      ,QR.[Offer_Update_Date] 
      ,QR.[Manufacturer] 
      ,QR.[Model] 
      ,QR.[Serial_Number] 
      ,QR.[Application_User_ID] 
      ,QR.[Application_ID] 
      ,QR.[device_Evaluation_Date] 
      ,QR.[Store_ID] 
      ,QR.[BAN] 
      ,QR.[Subscriber_No] 
      ,QR.[Offer_Amount] 
      ,QR.[RMA_Number] 
      ,QR.[Offer_Status] 
      ,QR.[Rejection_Reason] 
      ,QR.[RMA_Status] 
      ,QR.[Settlement_Amount] 
      ,QR.[Eligibility_Status] 
      ,QR.[Eligibility_Reason] 
      ,QR.[Adjustment_Reason] 
      ,QR.[Bill_Status] 
      ,QR.[Channel_ID] 
      ,QR.[Credit_Issue_Date] 
      ,QR.[Program_ID] 
      ,QR.[BulkID]
      ,QP.MARKET_ASSESSED_AMOUNT as [Fair Market Value] 
      ,QP.PRM_NAME AS Promo 
      ,QR.Assurant_Manufacturer as [Assurant Manufacturer Received] 
      ,QR.Assurant_Model as [Assurant Model Received]
      ,COALESCE(Q1.Answer_Name,'N/A') AS [FMiP OFF]
      ,COALESCE(Q6.Answer_Name,'N/A') AS [AntiTheft OFF]
      ,COALESCE(Q2.Answer_Name,'N/A') AS [Liquid Damage]
      ,COALESCE(Q3.Answer_Name,'N/A') AS [Promo Accepted]
      ,COALESCE(Q4.Answer_Name,'N/A') AS [LCD Acceptable]
      ,COALESCE(Q5.Answer_Name,'N/A') AS [Powers On]
    FROM [#Assurant Manufacturer Received] QR 
    LEFT JOIN ODS.[dbo].[QR_DR_TradeIn_Promo] QP ON QR.Offer_ID = QP.Offer_ID
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q1 ON QR.Offer_ID = Q1.Offer_ID AND Q1.Question_Name = 'Find My Iphone'--
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q2 ON QR.Offer_ID = Q2.Offer_ID AND Q2.Question_Name = 'Liquid Damage'
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q3 ON QR.Offer_ID = Q3.Offer_ID AND Q3.Question_Name = 'ATLANTIS_PROMO'
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q4 ON QR.Offer_ID = Q4.Offer_ID AND Q4.Question_Name = 'LCD Issue'
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q5 ON QR.Offer_ID = Q5.Offer_ID AND Q5.Question_Name = 'Powers On'
    LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q6 ON QR.Offer_ID = Q6.Offer_ID AND Q6.Question_Name = 'Anti Theft Disabled'

    You will need to create the following indexes to get good performance 
    [dbo].[QR_Device_Trade_In_Master_2016onward] (BAN, ImportFileDate)
    [dbo].[QR_Device_Trade_In_Master_2016onward] (BulkID , ImportFileDate)
    [dbo].[QR_Device_Trade_In_Master_2016onward] (Serial_Number, ImportFileDate)
    [dbo].[QR_Device_Trade_In_Master_2016onward] (Offer_Generate_Date, ImportFileDate)
    and maybe an index on  [#Assurant Manufacturer Received](Offer_Id) if you have a lot of rows on that table.
  • This could offer a perf lift:


    SELECT QR.[Offer_ID]
      ,QR.[Offer_Generate_Date]
      ,QR.[Offer_Update_Date]
      ,QR.[Manufacturer]
      ,QR.[Model]
      ,QR.[Serial_Number]
      ,QR.[Application_User_ID]
      ,QR.[Application_ID]
      ,QR.[device_Evaluation_Date]
      ,QR.[Store_ID]
      ,QR.[BAN]
      ,QR.[Subscriber_No]
      ,QR.[Offer_Amount]
      ,QR.[RMA_Number]
      ,QR.[Offer_Status]
      ,QR.[Rejection_Reason]
      ,QR.[RMA_Status]
      ,QR.[Settlement_Amount]
      ,QR.[Eligibility_Status]
      ,QR.[Eligibility_Reason]
      ,QR.[Adjustment_Reason]
      ,QR.[Bill_Status]
      ,QR.[Channel_ID]
      ,QR.[Credit_Issue_Date]
      ,QR.[Program_ID]
      ,QR.[BulkID]
      ,QP.MARKET_ASSESSED_AMOUNT as [Fair Market Value]
      ,QP.PRM_NAME AS Promo
      ,QR.Assurant_Manufacturer as [Assurant Manufacturer Received]
      ,QR.Assurant_Model as [Assurant Model Received]
      ,COALESCE(qn.Q1_Answer_Name,'N/A') AS [FMiP OFF]
      ,COALESCE(qn.Q6_Answer_Name,'N/A') AS [AntiTheft OFF]
      ,COALESCE(qn.Q2_Answer_Name,'N/A') AS [Liquid Damage]
      ,COALESCE(qn.Q3_Answer_Name,'N/A') AS [Promo Accepted]
      ,COALESCE(qn.Q4_Answer_Name,'N/A') AS [LCD Acceptable]
      ,COALESCE(qn.Q5_Answer_Name,'N/A') AS [Powers On]
    FROM [#Assurant Manufacturer Received] QR
    LEFT JOIN ODS.[dbo].[QR_DR_TradeIn_Promo] QP ON QR.Offer_ID = QP.Offer_ID
    OUTER APPLY (
     SELECT
      Q1_Answer_Name = MAX(CASE WHEN Q1.Question_Name = 'Find My Iphone' THEN Q1.Answer_Name END),
      Q2_Answer_Name = MAX(CASE WHEN Q1.Question_Name = 'Liquid Damage' THEN Q1.Answer_Name END),
      Q3_Answer_Name = MAX(CASE WHEN Q1.Question_Name = 'ATLANTIS_PROMO' THEN Q1.Answer_Name END),
      Q4_Answer_Name = MAX(CASE WHEN Q1.Question_Name = 'LCD Issue' THEN Q1.Answer_Name END),
      Q5_Answer_Name = MAX(CASE WHEN Q1.Question_Name = 'Powers On' THEN Q1.Answer_Name END),
      Q6_Answer_Name = MAX(CASE WHEN Q1.Question_Name = 'Anti Theft Disabled' THEN Q1.Answer_Name END)
     FROM ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q1
     WHERE QR.Offer_ID = Q1.Offer_ID
      AND Q1.Question_Name IN ('Find My Iphone', 'Liquid Damage', 'ATLANTIS_PROMO', 'LCD Issue', 'Powers On', 'Anti Theft Disabled')
    ) qn

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • Has the OP stated that the correct where clause is
    WHERE ( 
    BAN = @LOC_BAN 
    OR BulkID = @LOC_BulkId 
    OR Serial_Number= @LOC_IMEI 
    OR ([Offer_Generate_Date] >= @LOC_STARTOFFER AND [Offer_Generate_Date] <= @LOC_ENDOFFER)
    )
    AND ImportFileDate > getdate() - 180

    and not his original one? e.g. ImportFileDate applying to ALL other filters, not just the Offer_Generate_Date

    It does make a significant different but I have not seen the OP agree with the above.

  • Very exciting development. The specific UNION solution Jonathan AC Roberts supplied is currently (it's midnight) is showing a lot of promise, between lightening fast. 00:00:00 ms and 9 sec, when I pass BulkID or BAN.  (Not quite fast enough when I supply IMEI / 19 sec or dates /16 sec  but a huge improvement)

    Interestingly & Suprisingly,  frederico-fonseca's application of UNIONs with cte is very slow (yes I specified column names instead of SELECT *) yet I would have expected it to have similar performance!

    ** Attached are execution plans for when I passed BulkID value**  
    (1) During temp table INSERTs a covering Non Clustered index, that I once created but up til now was getting ignored, called idx_BTI_include is getting used PLUS the Clustered Index on QueryID (don't understand why)  PLUS BAN NonClustered  PLUS Seriel_Number NonClustered  .. but the BulkID NonClustered   is not used, even though it is the BulkID parameter for which I supplied value.  Are index hints advisable here in each UNION query?
    (2) During final query execution, Clustered Indexes from both tables in the JOIN on OfferID are called to action and this makes sense.

    --Here's the Jonathan AC Roberts query that I'm excited about.
    BTW, ImportFileDate > getdate() - 180 is something I removed within 10 min of posting report query / sorry for confusion. I am considering using only if I have to / but not preferred)


    USE [DistributionCenterFeed]
    GO


    DECLARE
        @BULKID      varchar(50) =  5006,
     @BAN   varchar(50) =  null, --'955932237',
     @FROM_DATE  date = NULL,
     @TO_DATE  date = NULL,
     @IMEI      varchar(100) = NULL;


     IF OBJECT_ID('tempdb..[#Assurant Manufacturer Received]','U') IS NOT NULL
      DROP TABLE [#Assurant Manufacturer Received];

    CREATE TABLE [#Assurant Manufacturer Received]
    (
      [Offer_ID] [varchar](500) NULL,
      [Offer_Generate_Date] [datetime] NULL,
      [Offer_Update_Date] [datetime] NULL,
      [Manufacturer] [varchar](300) NOT NULL,
      [Model] [varchar](300) NOT NULL,
      [Serial_Number] [varchar](100) NOT NULL,
      [Application_User_ID] [varchar](500) NULL,
      [Application_ID] [varchar](500) NULL,
      [device_Evaluation_Date] [datetime] NULL,
      [Store_ID] [varchar](100) NULL,
      [BAN] [numeric](9, 0) NULL,
      [Subscriber_No] [varchar](20) NULL,
      [Offer_Amount] [numeric](8, 4) NULL,
      [RMA_Number] [varchar](100) NULL,
      [Offer_Status] [varchar](100) NULL,
      [Rejection_Reason] [varchar](300) NULL,
      [RMA_Status] [varchar](100) NULL,
      [Settlement_Amount] [numeric](8, 4) NULL,
      [Eligibility_Status] [varchar](100) NULL,
      [Eligibility_Reason] [varchar](1000) NULL,
      [Adjustment_Reason]  [varchar](100),
      [Bill_Status] [varchar](1) NULL,
      [Channel_ID] [varchar](500) NULL,
      [Credit_Issue_Date] datetime,
      [Program_ID] varchar(10),
      [BulkID] varchar(50),
      [Assurant_Manufacturer] [varchar](300) NULL,
      [Assurant_Model] [varchar](300) NULL
    );

    INSERT INTO [#Assurant Manufacturer Received]
    (
      [Offer_ID],
      [Offer_Generate_Date],
      [Offer_Update_Date],
      [Manufacturer],
      [Model],
      [Serial_Number],
      [Application_User_ID],
      [Application_ID],
      [device_Evaluation_Date],
      [Store_ID],
      [BAN],
      [Subscriber_No],
      [Offer_Amount],
      [RMA_Number],
      [Offer_Status],
      [Rejection_Reason],
      [RMA_Status],
      [Settlement_Amount],
      [Eligibility_Status],
      [Eligibility_Reason],
      [Adjustment_Reason],
      [Bill_Status],
      [Channel_ID],
      [Credit_Issue_Date],
      [Program_ID],
      [BulkID],
      [Assurant_Manufacturer],
      [Assurant_Model]
    )
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
      FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
     WHERE QR.BAN = @BAN
     UNION
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
      FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
    WHERE QR.BulkID = @BULKID
    UNION
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
      FROM DistributionCenterFeed.[dbo].[QR_Device_Trade_In_Master_2016onward] QR
     WHERE QR.Serial_Number = @IMEI
     UNION
    SELECT QR.[Offer_ID],
      QR.[Offer_Generate_Date],
      QR.[Offer_Update_Date],
      QR.[Manufacturer],
      QR.[Model],
      QR.[Serial_Number],
      QR.[Application_User_ID],
      QR.[Application_ID],
      QR.[device_Evaluation_Date],
      QR.[Store_ID],
      QR.[BAN],
      QR.[Subscriber_No],
      QR.[Offer_Amount],
      QR.[RMA_Number],
      QR.[Offer_Status],
      QR.[Rejection_Reason],
      QR.[RMA_Status],
      QR.[Settlement_Amount],
      QR.[Eligibility_Status],
      QR.[Eligibility_Reason],
      QR.[Adjustment_Reason],
      QR.[Bill_Status],
      QR.[Channel_ID],
      QR.[Credit_Issue_Date],
      QR.[Program_ID],
      QR.[BulkID],
      QR.Assurant_Manufacturer AS [Assurant Manufacturer Received],
      QR.Assurant_Model AS [Assurant Model Received]
      FROM [#Assurant Manufacturer Received] QR
      WHERE QR.[Offer_Generate_Date] BETWEEN @FROM_DATE AND @TO_DATE;

    SELECT QR.[Offer_ID]
      ,QR.[Offer_Generate_Date]
      ,QR.[Offer_Update_Date]
      ,QR.[Manufacturer]
      ,QR.[Model]
      ,QR.[Serial_Number]
      ,QR.[Application_User_ID]
      ,QR.[Application_ID]
      ,QR.[device_Evaluation_Date]
      ,QR.[Store_ID]
      ,QR.[BAN]
      ,QR.[Subscriber_No]
      ,QR.[Offer_Amount]
      ,QR.[RMA_Number]
      ,QR.[Offer_Status]
      ,QR.[Rejection_Reason]
      ,QR.[RMA_Status]
      ,QR.[Settlement_Amount]
      ,QR.[Eligibility_Status]
      ,QR.[Eligibility_Reason]
      ,QR.[Adjustment_Reason]
      ,QR.[Bill_Status]
      ,QR.[Channel_ID]
      ,QR.[Credit_Issue_Date]
      ,QR.[Program_ID]
      ,QR.[BulkID]
      ,QP.MARKET_ASSESSED_AMOUNT as [Fair Market Value]
      ,QP.PRM_NAME AS Promo
      ,QR.Assurant_Manufacturer as [Assurant Manufacturer Received]
      ,QR.Assurant_Model as [Assurant Model Received]
      ,COALESCE(Q1.Answer_Name,'N/A') AS [FMiP OFF]
      ,COALESCE(Q6.Answer_Name,'N/A') AS [AntiTheft OFF]
      ,COALESCE(Q2.Answer_Name,'N/A') AS [Liquid Damage]
      ,COALESCE(Q3.Answer_Name,'N/A') AS [Promo Accepted]
      ,COALESCE(Q4.Answer_Name,'N/A') AS [LCD Acceptable]
      ,COALESCE(Q5.Answer_Name,'N/A') AS [Powers On]
      FROM [#Assurant Manufacturer Received] QR
      LEFT JOIN ODS.[dbo].[QR_DR_TradeIn_Promo] QP ON QR.Offer_ID = QP.Offer_ID
      LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q1 ON QR.Offer_ID = Q1.Offer_ID AND Q1.Question_Name = 'Find My Iphone'--
      LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q2 ON QR.Offer_ID = Q2.Offer_ID AND Q2.Question_Name = 'Liquid Damage'
      LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q3 ON QR.Offer_ID = Q3.Offer_ID AND Q3.Question_Name = 'ATLANTIS_PROMO'
      LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q4 ON QR.Offer_ID = Q4.Offer_ID AND Q4.Question_Name = 'LCD Issue'
      LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q5 ON QR.Offer_ID = Q5.Offer_ID AND Q5.Question_Name = 'Powers On'
      LEFT JOIN ODS.[dbo].[QR_DR_Transaction_Ques_Answers] Q6 ON QR.Offer_ID = Q6.Offer_ID AND Q6.Question_Name = 'Anti Theft Disabled'
     

    Non clustered covering index:

    USE [DistributionCenterFeed]
    GO

    /****** Object:  Index [idx_BTI_include]    Script Date: 11/28/2018 11:58:24 PM ******/
    CREATE NONCLUSTERED INDEX [idx_BTI_include] ON [dbo].[QR_Device_Trade_In_Master_2016onward]
    (
     [BulkID] ASC
    )
    INCLUDE (  [Offer_ID],
     [Offer_Generate_Date],
     [Offer_Update_Date],
     [Manufacturer],
     [Model],
     [Serial_Number],
     [Application_User_ID],
     [Application_ID],
     [device_Evaluation_Date],
     [Store_ID],
     [BAN],
     [Subscriber_No],
     [Offer_Amount],
     [RMA_Number],
     [Offer_Status],
     [Rejection_Reason],
     [RMA_Status],
     [Settlement_Amount],
     [Eligibility_Status],
     [Eligibility_Reason],
     [Adjustment_Reason],
     [Bill_Status],
     [Channel_ID],
     [Credit_Issue_Date],
     [Assurant_Model],
     [Assurant_Manufacturer],
     [Program_ID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
    GO

    --Quote me

  • Good progress.

    I would however like to see both explain plans for my code (changing the union all to union) and Jonathan's with indexes without included columns.
    for the volumes of rows returned you mentioned I do not think they are needed.

    e.g. the ones I posted earlier but with removal of ImportFileDate_Offer_Generate_Date as you said this is no longer needed.

    Temp tables vs CTE can change the plans a lot - and the step up from a CTE is going to a temp table

Viewing 15 posts - 16 through 30 (of 54 total)

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