Multiple queries in one

  • Hi

    I have a table with the following structure:

    CREATE TABLE [dbo].[SellerFeedbacks](

    [IdSeller] [varchar](50) NOT NULL,

    [Date] Date NOT NULL,

    [Feedback30Count] [int] NOT NULL,

    [Feedback30Positive] [int] NOT NULL,

    [Feedback90Count] [int] NOT NULL,

    [Feedback90Positive] [int] NOT NULL,

    [Feedback365Count] [int] NOT NULL,

    [Feedback365Positive] [int] NOT NULL,

     CONSTRAINT [PK_SellerFeedbacks] PRIMARY KEY CLUSTERED 

    (

    [IdSeller] ASC,

    [Date] ASC

    )


    Every month this table gets over 7.000.000 rows.
    There's a query that gets the 30 day feedback from today, a month ago, two months ago, ....
    But it's a RBAR and each query is executed once:

    DECLARE @Date DATE = GETDATE();
    /* use a cursor to get seller id from certain conditions
    and iterate the cursor */
    SELECT TOP 1 @Feedback30Count_1 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -1, @Date) ORDER BY Date DESC;
    SELECT TOP 1 @Feedback30Count_2 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -2, @Date) ORDER BY Date DESC;

    Is there a way of putting those two queries in just one?
    I'll try to get rid of the RBAR later...

    Thanks,
    Pedro

    PS: I can't edit the table structure since it's being used by an ETL external process that another department made. Just add indexes...

    • This topic was modified 4 years, 9 months ago by  Dave Convery.



    If you need to work better, try working less...

  • Couldn't you just UNION the two together?

    "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

  • Grant Fritchey - Thursday, September 13, 2018 6:12 AM

    Couldn't you just UNION the two together?

    Yes but that will read the table twice, won't it?
    I thought of making a ROW_NUMBER() with a PARTITION on the year/month of date and getting the first row but that would also probably read the entire table (340.000.000 rows...)
    The TOP 1 with IdSeller and Date < .. is quite fast for a single record but it uses RBAR, for 300.000 rows, which is very slow, but removing the cycle with TOP and ORDER Date DESC isn't simple (if even possible...)



    If you need to work better, try working less...

  • PiMané - Thursday, September 13, 2018 2:50 AM

    Hi

    I have a table with the following structure:

    CREATE TABLE [dbo].[SellerFeedbacks](

    [IdSeller] [varchar](50) NOT NULL,

    [Date] Date NOT NULL,

    [Feedback30Count] [int] NOT NULL,

    [Feedback30Positive] [int] NOT NULL,

    [Feedback90Count] [int] NOT NULL,

    [Feedback90Positive] [int] NOT NULL,

    [Feedback365Count] [int] NOT NULL,

    [Feedback365Positive] [int] NOT NULL,

     CONSTRAINT [PK_SellerFeedbacks] PRIMARY KEY CLUSTERED 

    (

    [IdSeller] ASC,

    [Date] ASC

    )

    Every month this table gets over 7.000.000 rows.
    There's a query that gets the 30 day feedback from today, a month ago, two months ago, ....
    But it's a RBAR and each query is executed once:

    DECLARE @Date DATE = GETDATE();
    /* use a cursor to get seller id from certain conditions
    and iterate the cursor */
    SELECT TOP 1 @Feedback30Count_1 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -1, @Date) ORDER BY Date DESC;
    SELECT TOP 1 @Feedback30Count_2 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -2, @Date) ORDER BY Date DESC;

    Is there a way of putting those two queries in just one?
    I'll try to get rid of the RBAR later...

    Thanks,
    Pedro

    PS: I can't edit the table structure since it's being used by an ETL external process that another department made. Just add indexes...

    If you create an index this might be a faster way of retrieving all data for all IsSellers

    CREATE INDEX IX_SellerFeedbacks_IdSeller_Date ON SellerFeedbacks(IdSeller,Date) INCLUDE (Feedback30Count)
    GO
    ;WITH CTE AS
    (
      SELECT DISTINCT IdSeller
      FROM SellerFeedbacks
    )
    SELECT CTE.IdSeller,[1Month].Feedback30Count1Month, [2Month].Feedback30Count2Month
    FROM CTE
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count1Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -1, @Date)
         ORDER BY Date DESC) [1Month]
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count2Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -2, @Date)
         ORDER BY Date DESC) [2Month]

  • Jonathan AC Roberts - Thursday, September 13, 2018 6:59 AM

    PiMané - Thursday, September 13, 2018 2:50 AM

    Hi

    I have a table with the following structure:

    CREATE TABLE [dbo].[SellerFeedbacks](

    [IdSeller] [varchar](50) NOT NULL,

    [Date] Date NOT NULL,

    [Feedback30Count] [int] NOT NULL,

    [Feedback30Positive] [int] NOT NULL,

    [Feedback90Count] [int] NOT NULL,

    [Feedback90Positive] [int] NOT NULL,

    [Feedback365Count] [int] NOT NULL,

    [Feedback365Positive] [int] NOT NULL,

     CONSTRAINT [PK_SellerFeedbacks] PRIMARY KEY CLUSTERED 

    (

    [IdSeller] ASC,

    [Date] ASC

    )

    Every month this table gets over 7.000.000 rows.
    There's a query that gets the 30 day feedback from today, a month ago, two months ago, ....
    But it's a RBAR and each query is executed once:

    DECLARE @Date DATE = GETDATE();
    /* use a cursor to get seller id from certain conditions
    and iterate the cursor */
    SELECT TOP 1 @Feedback30Count_1 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -1, @Date) ORDER BY Date DESC;
    SELECT TOP 1 @Feedback30Count_2 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -2, @Date) ORDER BY Date DESC;

    Is there a way of putting those two queries in just one?
    I'll try to get rid of the RBAR later...

    Thanks,
    Pedro

    PS: I can't edit the table structure since it's being used by an ETL external process that another department made. Just add indexes...

    If you create an index this might be a faster way of retrieving all data for all IsSellers

    CREATE INDEX IX_SellerFeedbacks_IdSeller_Date ON SellerFeedbacks(IdSeller,Date) INCLUDE (Feedback30Count)
    GO
    ;WITH CTE AS
    (
      SELECT DISTINCT IdSeller
      FROM SellerFeedbacks
    )
    SELECT CTE.IdSeller,[1Month].Feedback30Count1Month, [2Month].Feedback30Count2Month
    FROM CTE
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count1Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -1, @Date)
         ORDER BY Date DESC) [1Month]
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count2Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -2, @Date)
         ORDER BY Date DESC) [2Month]

    With a small change I managed to remove the RBAR.. Thanks a lot!!! 😀



    If you need to work better, try working less...

  • PiMané - Thursday, September 13, 2018 7:38 AM

    Jonathan AC Roberts - Thursday, September 13, 2018 6:59 AM

    PiMané - Thursday, September 13, 2018 2:50 AM

    Hi

    I have a table with the following structure:

    CREATE TABLE [dbo].[SellerFeedbacks](

    [IdSeller] [varchar](50) NOT NULL,

    [Date] Date NOT NULL,

    [Feedback30Count] [int] NOT NULL,

    [Feedback30Positive] [int] NOT NULL,

    [Feedback90Count] [int] NOT NULL,

    [Feedback90Positive] [int] NOT NULL,

    [Feedback365Count] [int] NOT NULL,

    [Feedback365Positive] [int] NOT NULL,

     CONSTRAINT [PK_SellerFeedbacks] PRIMARY KEY CLUSTERED 

    (

    [IdSeller] ASC,

    [Date] ASC

    )

    Every month this table gets over 7.000.000 rows.
    There's a query that gets the 30 day feedback from today, a month ago, two months ago, ....
    But it's a RBAR and each query is executed once:

    DECLARE @Date DATE = GETDATE();
    /* use a cursor to get seller id from certain conditions
    and iterate the cursor */
    SELECT TOP 1 @Feedback30Count_1 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -1, @Date) ORDER BY Date DESC;
    SELECT TOP 1 @Feedback30Count_2 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -2, @Date) ORDER BY Date DESC;

    Is there a way of putting those two queries in just one?
    I'll try to get rid of the RBAR later...

    Thanks,
    Pedro

    PS: I can't edit the table structure since it's being used by an ETL external process that another department made. Just add indexes...

    If you create an index this might be a faster way of retrieving all data for all IsSellers

    CREATE INDEX IX_SellerFeedbacks_IdSeller_Date ON SellerFeedbacks(IdSeller,Date) INCLUDE (Feedback30Count)
    GO
    ;WITH CTE AS
    (
      SELECT DISTINCT IdSeller
      FROM SellerFeedbacks
    )
    SELECT CTE.IdSeller,[1Month].Feedback30Count1Month, [2Month].Feedback30Count2Month
    FROM CTE
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count1Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -1, @Date)
         ORDER BY Date DESC) [1Month]
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count2Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -2, @Date)
         ORDER BY Date DESC) [2Month]

    With a small change I managed to remove the RBAR.. Thanks a lot!!! 😀

    What was your small change?

  • Jonathan AC Roberts - Thursday, September 13, 2018 7:51 AM

    PiMané - Thursday, September 13, 2018 7:38 AM

    Jonathan AC Roberts - Thursday, September 13, 2018 6:59 AM

    PiMané - Thursday, September 13, 2018 2:50 AM

    Hi

    I have a table with the following structure:

    CREATE TABLE [dbo].[SellerFeedbacks](

    [IdSeller] [varchar](50) NOT NULL,

    [Date] Date NOT NULL,

    [Feedback30Count] [int] NOT NULL,

    [Feedback30Positive] [int] NOT NULL,

    [Feedback90Count] [int] NOT NULL,

    [Feedback90Positive] [int] NOT NULL,

    [Feedback365Count] [int] NOT NULL,

    [Feedback365Positive] [int] NOT NULL,

     CONSTRAINT [PK_SellerFeedbacks] PRIMARY KEY CLUSTERED 

    (

    [IdSeller] ASC,

    [Date] ASC

    )

    Every month this table gets over 7.000.000 rows.
    There's a query that gets the 30 day feedback from today, a month ago, two months ago, ....
    But it's a RBAR and each query is executed once:

    DECLARE @Date DATE = GETDATE();
    /* use a cursor to get seller id from certain conditions
    and iterate the cursor */
    SELECT TOP 1 @Feedback30Count_1 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -1, @Date) ORDER BY Date DESC;
    SELECT TOP 1 @Feedback30Count_2 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -2, @Date) ORDER BY Date DESC;

    Is there a way of putting those two queries in just one?
    I'll try to get rid of the RBAR later...

    Thanks,
    Pedro

    PS: I can't edit the table structure since it's being used by an ETL external process that another department made. Just add indexes...

    If you create an index this might be a faster way of retrieving all data for all IsSellers

    CREATE INDEX IX_SellerFeedbacks_IdSeller_Date ON SellerFeedbacks(IdSeller,Date) INCLUDE (Feedback30Count)
    GO
    ;WITH CTE AS
    (
      SELECT DISTINCT IdSeller
      FROM SellerFeedbacks
    )
    SELECT CTE.IdSeller,[1Month].Feedback30Count1Month, [2Month].Feedback30Count2Month
    FROM CTE
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count1Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -1, @Date)
         ORDER BY Date DESC) [1Month]
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count2Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -2, @Date)
         ORDER BY Date DESC) [2Month]

    With a small change I managed to remove the RBAR.. Thanks a lot!!! 😀

    What was your small change?

    Where you have WHERE IdSeller = @IdSeller I replaced with WHERE IdSeller = CTE.IdSeller
    My concern is that the OUTER APPLY might behave like a scalar function .



    If you need to work better, try working less...

  • PiMané - Thursday, September 13, 2018 7:55 AM

    Jonathan AC Roberts - Thursday, September 13, 2018 7:51 AM

    PiMané - Thursday, September 13, 2018 7:38 AM

    Jonathan AC Roberts - Thursday, September 13, 2018 6:59 AM

    PiMané - Thursday, September 13, 2018 2:50 AM

    Hi

    I have a table with the following structure:

    CREATE TABLE [dbo].[SellerFeedbacks](

    [IdSeller] [varchar](50) NOT NULL,

    [Date] Date NOT NULL,

    [Feedback30Count] [int] NOT NULL,

    [Feedback30Positive] [int] NOT NULL,

    [Feedback90Count] [int] NOT NULL,

    [Feedback90Positive] [int] NOT NULL,

    [Feedback365Count] [int] NOT NULL,

    [Feedback365Positive] [int] NOT NULL,

     CONSTRAINT [PK_SellerFeedbacks] PRIMARY KEY CLUSTERED 

    (

    [IdSeller] ASC,

    [Date] ASC

    )

    Every month this table gets over 7.000.000 rows.
    There's a query that gets the 30 day feedback from today, a month ago, two months ago, ....
    But it's a RBAR and each query is executed once:

    DECLARE @Date DATE = GETDATE();
    /* use a cursor to get seller id from certain conditions
    and iterate the cursor */
    SELECT TOP 1 @Feedback30Count_1 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -1, @Date) ORDER BY Date DESC;
    SELECT TOP 1 @Feedback30Count_2 = Feedback30Count FROM SellerFeedbacks (NOLOCK) WHERE IdSeller = @IdSeller AND Date < DATEADD(month, -2, @Date) ORDER BY Date DESC;

    Is there a way of putting those two queries in just one?
    I'll try to get rid of the RBAR later...

    Thanks,
    Pedro

    PS: I can't edit the table structure since it's being used by an ETL external process that another department made. Just add indexes...

    If you create an index this might be a faster way of retrieving all data for all IsSellers

    CREATE INDEX IX_SellerFeedbacks_IdSeller_Date ON SellerFeedbacks(IdSeller,Date) INCLUDE (Feedback30Count)
    GO
    ;WITH CTE AS
    (
      SELECT DISTINCT IdSeller
      FROM SellerFeedbacks
    )
    SELECT CTE.IdSeller,[1Month].Feedback30Count1Month, [2Month].Feedback30Count2Month
    FROM CTE
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count1Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -1, @Date)
         ORDER BY Date DESC) [1Month]
    OUTER APPLY(SELECT TOP(1) Feedback30Count Feedback30Count2Month
         FROM SellerFeedbacks
         WHERE IdSeller = @IdSeller
         AND Date < DATEADD(month, -2, @Date)
         ORDER BY Date DESC) [2Month]

    With a small change I managed to remove the RBAR.. Thanks a lot!!! 😀

    What was your small change?

    Where you have WHERE IdSeller = @IdSeller I replaced with WHERE IdSeller = CTE.IdSeller
    My concern is that the OUTER APPLY might behave like a scalar function .

    Oh yes, well spotted, I thought I'd put that.
    OUTER APPLY behaves much like a left join. If you put the index on I said and have a look at the execution plan you will see it does a seek to get the value.

  • Will do thank 🙂
    The problem is that right now I can't test it since an index on this table takes almost 1h to create... It has 340.000.000 rows and it's a "low" azure instance.



    If you need to work better, try working less...

  • PiMané - Thursday, September 13, 2018 8:05 AM

    Will do thank 🙂
    The problem is that right now I can't test it since an index on this table takes almost 1h to create... It has 340.000.000 rows and it's a "low" azure instance.

    You'll get a big performance improvement from the index, so it's worth trying to add it.

Viewing 10 posts - 1 through 9 (of 9 total)

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