Select * from View takes 4 minutesImproving performance of a viewI've created a view for a report, it now takes 30 minutes to run - Any ideas?Optimizing query. FOR XML PATH or some alternatives?Row estimates always too lowBad performance using “NOT IN”Why is selecting all resulting columns of this query faster than selecting the one column I care about?Query Locks Table And Takes Long Time to RunWhy is this faster and is it safe to use? (WHERE first letter is in the alphabet)Warning in Execution PlanSQL Server statement takes forever while running instantly in Oracle

Why is there a need to modify system call tables in Linux?

Joist hangers to use for rough cut 2x8 (2 3/4" x 8 3/4")?

Asking for something with different prices

Are grass strips more dangerous than tarmac?

The qvolume of an integer

How do I set the Verbatim font (or the mono font) to bold by default?

What people are called "кабан" and why?

Is it possible to track/save Google searches that were never submitted?

What if you don't bring your credit card or debit for incidentals?

Accidentally cashed a check twice

TV show or movie: Diseased people are exiled to a spaceship

Can I ask a publisher for a paper that I need for reviewing

Can an old DSLR be upgraded to match modern smartphone image quality

Coding Challenge Solution - Good Range

Do adult Russians normally hand-write Cyrillic as cursive or as block letters?

Can The Malloreon be read without first reading The Belgariad?

What is the intuition behind uniform continuity?

Pros and cons of writing a book review?

Humans meet a distant alien species. How do they standardize? - Units of Measure

How crucial is a waifu game storyline?

What does War Machine's "Canopy! Canopy!" line mean in "Avengers: Endgame"?

How did the Zip Chip and RocketChip accelerators work for the Apple II?

Is American Express widely accepted in France?

Is the capacitor drawn or wired wrongly?



Select * from View takes 4 minutes


Improving performance of a viewI've created a view for a report, it now takes 30 minutes to run - Any ideas?Optimizing query. FOR XML PATH or some alternatives?Row estimates always too lowBad performance using “NOT IN”Why is selecting all resulting columns of this query faster than selecting the one column I care about?Query Locks Table And Takes Long Time to RunWhy is this faster and is it safe to use? (WHERE first letter is in the alphabet)Warning in Execution PlanSQL Server statement takes forever while running instantly in Oracle






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








5















I am running in to an issue where when I run a query against a view it takes 4+ minutes. However, when I run the guts of the query it finishes in like 1 second.



The only thing I am not sure about is the tables being joined are both temporal tables.



Ad hoc query plan:
https://www.brentozar.com/pastetheplan/?id=BykohB2p4



View query plan:
https://www.brentozar.com/pastetheplan/?id=SkIfTHh6E



Any suggestions on where to try and figure this out?



View code:



ALTER VIEW [dbo].[vwDealHistoryPITA]
AS
SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.LastUpdateDate) AS Deal_HistoryID,
cm.CodeMasterID,
cm.ProjectName,
cm.[Status],
d.CompanyID,
d.DealTypeMasterID,
cm.[Description],
d.PassiveInd,
d.ApproxTPGOwnership,
d.NumberBoardSeats,
d.FollowonInvestmentInd,
d.SocialImpactInd,
d.EquityInd,
d.DebtInd,
d.RealEstateInd,
d.TargetPctgReturn,
d.ApproxTotalDealSize,
cm.CurrencyCode,
d.ConflictCheck,
cm.CreatedDate,
cm.CreatedBy,
cm.LastUpdateDate,
cm.LastUpdateBy,
d.ExpensesExceedThresholdDate,
d.CurrentTPGCheckSize,
d.PreferredEquityInd,
d.ConvertibleDebtInd,
d.OtherRealAssetsInd,
d.InitialTPGCheckSize,
d.DirectLendingInd,
cm.NameApproved,
cm.FolderID,
cm.CodaProcessedDateTime,
cm.DeadDate,
d.SectorMasterID,
d.DTODataCompleteDate,
cm.ValidFrom AS CodeMasterValidFrom,
cm.ValidTo AS CodeMasterValidTo,
d.validFrom AS DealValidFrom,
d.validTo AS DealValidTo
FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID;
GO


Added the Partition by and get similar results to the ad hoc query.










share|improve this question
























  • Can you post the view definition ? What version of sql server are you using ? Also, does a recompile of view fix the issue ?

    – Kin Shah
    7 hours ago











  • Edited the post with the view code and potential solution.

    – user761786
    6 hours ago

















5















I am running in to an issue where when I run a query against a view it takes 4+ minutes. However, when I run the guts of the query it finishes in like 1 second.



The only thing I am not sure about is the tables being joined are both temporal tables.



Ad hoc query plan:
https://www.brentozar.com/pastetheplan/?id=BykohB2p4



View query plan:
https://www.brentozar.com/pastetheplan/?id=SkIfTHh6E



Any suggestions on where to try and figure this out?



View code:



ALTER VIEW [dbo].[vwDealHistoryPITA]
AS
SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.LastUpdateDate) AS Deal_HistoryID,
cm.CodeMasterID,
cm.ProjectName,
cm.[Status],
d.CompanyID,
d.DealTypeMasterID,
cm.[Description],
d.PassiveInd,
d.ApproxTPGOwnership,
d.NumberBoardSeats,
d.FollowonInvestmentInd,
d.SocialImpactInd,
d.EquityInd,
d.DebtInd,
d.RealEstateInd,
d.TargetPctgReturn,
d.ApproxTotalDealSize,
cm.CurrencyCode,
d.ConflictCheck,
cm.CreatedDate,
cm.CreatedBy,
cm.LastUpdateDate,
cm.LastUpdateBy,
d.ExpensesExceedThresholdDate,
d.CurrentTPGCheckSize,
d.PreferredEquityInd,
d.ConvertibleDebtInd,
d.OtherRealAssetsInd,
d.InitialTPGCheckSize,
d.DirectLendingInd,
cm.NameApproved,
cm.FolderID,
cm.CodaProcessedDateTime,
cm.DeadDate,
d.SectorMasterID,
d.DTODataCompleteDate,
cm.ValidFrom AS CodeMasterValidFrom,
cm.ValidTo AS CodeMasterValidTo,
d.validFrom AS DealValidFrom,
d.validTo AS DealValidTo
FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID;
GO


Added the Partition by and get similar results to the ad hoc query.










share|improve this question
























  • Can you post the view definition ? What version of sql server are you using ? Also, does a recompile of view fix the issue ?

    – Kin Shah
    7 hours ago











  • Edited the post with the view code and potential solution.

    – user761786
    6 hours ago













5












5








5


2






I am running in to an issue where when I run a query against a view it takes 4+ minutes. However, when I run the guts of the query it finishes in like 1 second.



The only thing I am not sure about is the tables being joined are both temporal tables.



Ad hoc query plan:
https://www.brentozar.com/pastetheplan/?id=BykohB2p4



View query plan:
https://www.brentozar.com/pastetheplan/?id=SkIfTHh6E



Any suggestions on where to try and figure this out?



View code:



ALTER VIEW [dbo].[vwDealHistoryPITA]
AS
SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.LastUpdateDate) AS Deal_HistoryID,
cm.CodeMasterID,
cm.ProjectName,
cm.[Status],
d.CompanyID,
d.DealTypeMasterID,
cm.[Description],
d.PassiveInd,
d.ApproxTPGOwnership,
d.NumberBoardSeats,
d.FollowonInvestmentInd,
d.SocialImpactInd,
d.EquityInd,
d.DebtInd,
d.RealEstateInd,
d.TargetPctgReturn,
d.ApproxTotalDealSize,
cm.CurrencyCode,
d.ConflictCheck,
cm.CreatedDate,
cm.CreatedBy,
cm.LastUpdateDate,
cm.LastUpdateBy,
d.ExpensesExceedThresholdDate,
d.CurrentTPGCheckSize,
d.PreferredEquityInd,
d.ConvertibleDebtInd,
d.OtherRealAssetsInd,
d.InitialTPGCheckSize,
d.DirectLendingInd,
cm.NameApproved,
cm.FolderID,
cm.CodaProcessedDateTime,
cm.DeadDate,
d.SectorMasterID,
d.DTODataCompleteDate,
cm.ValidFrom AS CodeMasterValidFrom,
cm.ValidTo AS CodeMasterValidTo,
d.validFrom AS DealValidFrom,
d.validTo AS DealValidTo
FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID;
GO


Added the Partition by and get similar results to the ad hoc query.










share|improve this question
















I am running in to an issue where when I run a query against a view it takes 4+ minutes. However, when I run the guts of the query it finishes in like 1 second.



The only thing I am not sure about is the tables being joined are both temporal tables.



Ad hoc query plan:
https://www.brentozar.com/pastetheplan/?id=BykohB2p4



View query plan:
https://www.brentozar.com/pastetheplan/?id=SkIfTHh6E



Any suggestions on where to try and figure this out?



View code:



ALTER VIEW [dbo].[vwDealHistoryPITA]
AS
SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.LastUpdateDate) AS Deal_HistoryID,
cm.CodeMasterID,
cm.ProjectName,
cm.[Status],
d.CompanyID,
d.DealTypeMasterID,
cm.[Description],
d.PassiveInd,
d.ApproxTPGOwnership,
d.NumberBoardSeats,
d.FollowonInvestmentInd,
d.SocialImpactInd,
d.EquityInd,
d.DebtInd,
d.RealEstateInd,
d.TargetPctgReturn,
d.ApproxTotalDealSize,
cm.CurrencyCode,
d.ConflictCheck,
cm.CreatedDate,
cm.CreatedBy,
cm.LastUpdateDate,
cm.LastUpdateBy,
d.ExpensesExceedThresholdDate,
d.CurrentTPGCheckSize,
d.PreferredEquityInd,
d.ConvertibleDebtInd,
d.OtherRealAssetsInd,
d.InitialTPGCheckSize,
d.DirectLendingInd,
cm.NameApproved,
cm.FolderID,
cm.CodaProcessedDateTime,
cm.DeadDate,
d.SectorMasterID,
d.DTODataCompleteDate,
cm.ValidFrom AS CodeMasterValidFrom,
cm.ValidTo AS CodeMasterValidTo,
d.validFrom AS DealValidFrom,
d.validTo AS DealValidTo
FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID;
GO


Added the Partition by and get similar results to the ad hoc query.







sql-server






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 6 hours ago







user761786

















asked 8 hours ago









user761786user761786

3081310




3081310












  • Can you post the view definition ? What version of sql server are you using ? Also, does a recompile of view fix the issue ?

    – Kin Shah
    7 hours ago











  • Edited the post with the view code and potential solution.

    – user761786
    6 hours ago

















  • Can you post the view definition ? What version of sql server are you using ? Also, does a recompile of view fix the issue ?

    – Kin Shah
    7 hours ago











  • Edited the post with the view code and potential solution.

    – user761786
    6 hours ago
















Can you post the view definition ? What version of sql server are you using ? Also, does a recompile of view fix the issue ?

– Kin Shah
7 hours ago





Can you post the view definition ? What version of sql server are you using ? Also, does a recompile of view fix the issue ?

– Kin Shah
7 hours ago













Edited the post with the view code and potential solution.

– user761786
6 hours ago





Edited the post with the view code and potential solution.

– user761786
6 hours ago










1 Answer
1






active

oldest

votes


















5














The main performance differences



The main differences here are that the better performing query is pushing down the seek predicate on CodeMasterID on all 4 tables (2 temporal tables (actual & history)) where the select on the view appears to not do that until the end (filter operator).



TL DR;



The issue is due to to parameters not pushing down to window functions in certain cases such as views. The easiest solution is adding OPTION(RECOMPILE) to the view call as to make the optimizer 'see' the params at runtime if that is a possibility. If it is too expensive to recompile the execution plan for each query call, using an inline table valued function that expects a parameter could be a solution. There is an excellent Blogpost by Paul White on this. For a more detailed way on finding and resolving your particular issue, keep on reading.



The better performing query



Codemaster table



enter image description here



enter image description here



Deal table



enter image description here



enter image description here



I love the smell of seek predicates in the morning




The big bad query



Codemaster table



enter image description here



enter image description here



This is a predicate only zone



The Deal table



enter image description here



But the optimizer did not read 'The art of the deal™"



enter image description here



...and does not learn from the past



Until all that data reaches the filter operator



enter image description here




So, what gives?



The main problem here is the optimizer not 'seeing' the parameters at runtime due to the window functions in the view and not being able to use the SelOnSeqPrj (select on sequence project, further down in this post for reference).



I was able to replicate the same results with a test sample and using SP_EXECUTESQL to parameterize the call to the view. See addendum for the DDL / DML



executing a query against a test view with a window function and an INNER JOIN



SET STATISTICS IO, TIME ON;
EXEC SP_EXECUTESQL
N'SELECT * FROM dbo.Bad
Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155;


Resulting in about 4.5s of cpu time and 3.2s elapsed time



 SQL Server Execution Times:
CPU time = 4595 ms, elapsed time = 3209 ms.


When we add the sweet embrace of OPTION(RECOMPILE)



SET STATISTICS IO, TIME ON;
EXEC SP_EXECUTESQL
N'SELECT * FROM dbo.Bad
Where CodeMasterID = @P1 OPTION(RECOMPILE)',N'@P1 INT',@P1 = 37155;


It is all good.



 SQL Server Execution Times:
CPU time = 16 ms, elapsed time = 98 ms.


Why



This all again supports the point of not being able to apply the @P1 predicate to the tables because of the window function & parameterization resulting in the filter operator



enter image description hereenter image description here



Not only an issue for temporal tables



See addendum 2



Even when not using temporal tables, this happens:
enter image description here



The same result is seen when writing the query like this:



DECLARE @P1 int = 37155
SELECT * FROM dbo.Bad2
Where CodeMasterID = @P1;


Again, the optimizer is not pushing down the predicate before applying the window function.



When omitting the ROW_NUMBER()



CREATE VIEW dbo.Bad3
as
SELECT
cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
FROM dbo.CodeMaster2 cm
INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID;


All is well



SET STATISTICS IO, TIME ON;
EXEC SP_EXECUTESQL
N'SELECT * FROM dbo.Bad3
Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155


SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 33 ms.


so where does all that leave us?



The ROW_NUMBER() is calculated before the filter is applied on the bad queries.



And all this leads us to this blogpost from 2013 by Paul White
on window functions and views.



One of the important parts for our example is this statement:




Unfortunately, the SelOnSeqPrj simplification rule only works when the
predicate performs a comparison with a constant. For that reason, the
following query produces the sub-optimal plan on SQL Server 2008 and
later:




DECLARE @ProductID INT = 878;

SELECT
mrt.ProductID,
mrt.TransactionID,
mrt.ReferenceOrderID,
mrt.TransactionDate,
mrt.Quantity
FROM dbo.MostRecentTransactionsPerProduct AS mrt
WHERE
mrt.ProductID = @ProductID;


enter image description here



This part corresponds to what we have seen when declaring the parameter ourselves / using SP_EXECUTESQL on the view.




The actual solutions



OPTION(RECOMPILE)


We know that OPTION(RECOMPILE) to 'see' the value at runtime is a possibility. When recompiling the execution plan for each query call is too expensive, there are other solutions.



Inline table valued function with a parameter



CREATE FUNCTION dbo.BlaBla
(
@P1 INT
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
(
SELECT
ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
cm.CodeMasterID,CM.ManagerID,
cm.ParentDeptID,d.DealID,
d.CodeMasterID as dealcodemaster,
d.EvenMoreBlaID
FROM dbo.CodeMaster2 cm
INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
Where cm.CodeMasterID = @P1
)
EXEC SP_EXECUTESQL
N'SELECT * FROM dbo.BlaBLa(@P1)',N'@P1 INT',@P1 = 37155


Resulting in the expected seek predicates



 SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.


With about 9 logical reads on my test




Addendum #1



CREATE TABLE dbo.Codemaster 
(
CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
, ManagerID INT NULL
, ParentDeptID int NULL
, SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
, SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
, PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Codemaster_History))
;

CREATE TABLE dbo.Deal
(
DealID int NOT NULL PRIMARY KEY CLUSTERED
, CodeMasterID INT NULL
, EvenMoreBlaID int NULL
, SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
, SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
, PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Deal_History))
;

INSERT INTO dbo.Codemaster(CodeMasterID,ManagerID,ParentDeptID)
SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
FROM MASTER..spt_values as spt1
CROSS JOIN MASTER..spt_values as spt2;


INSERT INTO dbo.Deal(DealID,CodeMasterID,EvenMoreBlaID)
SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
FROM MASTER..spt_values as spt1
CROSS JOIN MASTER..spt_values as spt2;

CREATE INDEX IX_CodeMasterID
ON dbo.Deal(CodeMasterId);
CREATE INDEX IX_CodeMasterID
ON dbo.Deal_History(CodeMasterId);

CREATE INDEX IX_CodeMasterID
ON dbo.Codemaster(CodeMasterId);
CREATE INDEX IX_CodeMasterID
ON dbo.Codemaster_History(CodeMasterId);


SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
cm.*, d.*
FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID
Where cm.CodeMasterID = 37155;

-- Guud
GO
CREATE VIEW dbo.Bad
as
SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID

GO
EXEC SP_EXECUTESQL
N'SELECT * FROM dbo.Bad
Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155

-- Very bad shame on you



Addendum #2



CREATE TABLE dbo.Codemaster2
(
CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
, ManagerID INT NULL
, ParentDeptID int NULL

);

CREATE TABLE dbo.Deal2
(
DealID int NOT NULL PRIMARY KEY CLUSTERED
, CodeMasterID INT NULL
, EvenMoreBlaID int NULL
);

INSERT INTO dbo.Codemaster2(CodeMasterID,ManagerID,ParentDeptID)
SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
FROM MASTER..spt_values as spt1
CROSS JOIN MASTER..spt_values as spt2;


INSERT INTO dbo.Deal2(DealID,CodeMasterID,EvenMoreBlaID)
SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
FROM MASTER..spt_values as spt1
CROSS JOIN MASTER..spt_values as spt2;

CREATE INDEX IX_CodeMasterID
ON dbo.Deal2(CodeMasterId);
CREATE INDEX IX_CodeMasterID
ON dbo.Codemaster2(CodeMasterId);


SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterId) AS Deal_HistoryID,
cm.*, d.*
FROM dbo.CodeMaster2 cm
INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
Where cm.CodeMasterID = 37155;

-- Guud
GO
CREATE VIEW dbo.Bad2
as
SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
FROM dbo.CodeMaster2 cm
INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID

GO
SET STATISTICS IO, TIME ON;
EXEC SP_EXECUTESQL
N'SELECT * FROM dbo.Bad2
Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155





share|improve this answer

























    Your Answer








    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "182"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f239370%2fselect-from-view-takes-4-minutes%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5














    The main performance differences



    The main differences here are that the better performing query is pushing down the seek predicate on CodeMasterID on all 4 tables (2 temporal tables (actual & history)) where the select on the view appears to not do that until the end (filter operator).



    TL DR;



    The issue is due to to parameters not pushing down to window functions in certain cases such as views. The easiest solution is adding OPTION(RECOMPILE) to the view call as to make the optimizer 'see' the params at runtime if that is a possibility. If it is too expensive to recompile the execution plan for each query call, using an inline table valued function that expects a parameter could be a solution. There is an excellent Blogpost by Paul White on this. For a more detailed way on finding and resolving your particular issue, keep on reading.



    The better performing query



    Codemaster table



    enter image description here



    enter image description here



    Deal table



    enter image description here



    enter image description here



    I love the smell of seek predicates in the morning




    The big bad query



    Codemaster table



    enter image description here



    enter image description here



    This is a predicate only zone



    The Deal table



    enter image description here



    But the optimizer did not read 'The art of the deal™"



    enter image description here



    ...and does not learn from the past



    Until all that data reaches the filter operator



    enter image description here




    So, what gives?



    The main problem here is the optimizer not 'seeing' the parameters at runtime due to the window functions in the view and not being able to use the SelOnSeqPrj (select on sequence project, further down in this post for reference).



    I was able to replicate the same results with a test sample and using SP_EXECUTESQL to parameterize the call to the view. See addendum for the DDL / DML



    executing a query against a test view with a window function and an INNER JOIN



    SET STATISTICS IO, TIME ON;
    EXEC SP_EXECUTESQL
    N'SELECT * FROM dbo.Bad
    Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155;


    Resulting in about 4.5s of cpu time and 3.2s elapsed time



     SQL Server Execution Times:
    CPU time = 4595 ms, elapsed time = 3209 ms.


    When we add the sweet embrace of OPTION(RECOMPILE)



    SET STATISTICS IO, TIME ON;
    EXEC SP_EXECUTESQL
    N'SELECT * FROM dbo.Bad
    Where CodeMasterID = @P1 OPTION(RECOMPILE)',N'@P1 INT',@P1 = 37155;


    It is all good.



     SQL Server Execution Times:
    CPU time = 16 ms, elapsed time = 98 ms.


    Why



    This all again supports the point of not being able to apply the @P1 predicate to the tables because of the window function & parameterization resulting in the filter operator



    enter image description hereenter image description here



    Not only an issue for temporal tables



    See addendum 2



    Even when not using temporal tables, this happens:
    enter image description here



    The same result is seen when writing the query like this:



    DECLARE @P1 int = 37155
    SELECT * FROM dbo.Bad2
    Where CodeMasterID = @P1;


    Again, the optimizer is not pushing down the predicate before applying the window function.



    When omitting the ROW_NUMBER()



    CREATE VIEW dbo.Bad3
    as
    SELECT
    cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
    FROM dbo.CodeMaster2 cm
    INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID;


    All is well



    SET STATISTICS IO, TIME ON;
    EXEC SP_EXECUTESQL
    N'SELECT * FROM dbo.Bad3
    Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155


    SQL Server Execution Times:
    CPU time = 0 ms, elapsed time = 33 ms.


    so where does all that leave us?



    The ROW_NUMBER() is calculated before the filter is applied on the bad queries.



    And all this leads us to this blogpost from 2013 by Paul White
    on window functions and views.



    One of the important parts for our example is this statement:




    Unfortunately, the SelOnSeqPrj simplification rule only works when the
    predicate performs a comparison with a constant. For that reason, the
    following query produces the sub-optimal plan on SQL Server 2008 and
    later:




    DECLARE @ProductID INT = 878;

    SELECT
    mrt.ProductID,
    mrt.TransactionID,
    mrt.ReferenceOrderID,
    mrt.TransactionDate,
    mrt.Quantity
    FROM dbo.MostRecentTransactionsPerProduct AS mrt
    WHERE
    mrt.ProductID = @ProductID;


    enter image description here



    This part corresponds to what we have seen when declaring the parameter ourselves / using SP_EXECUTESQL on the view.




    The actual solutions



    OPTION(RECOMPILE)


    We know that OPTION(RECOMPILE) to 'see' the value at runtime is a possibility. When recompiling the execution plan for each query call is too expensive, there are other solutions.



    Inline table valued function with a parameter



    CREATE FUNCTION dbo.BlaBla
    (
    @P1 INT
    )
    RETURNS TABLE
    WITH SCHEMABINDING AS
    RETURN
    (
    SELECT
    ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
    cm.CodeMasterID,CM.ManagerID,
    cm.ParentDeptID,d.DealID,
    d.CodeMasterID as dealcodemaster,
    d.EvenMoreBlaID
    FROM dbo.CodeMaster2 cm
    INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
    Where cm.CodeMasterID = @P1
    )
    EXEC SP_EXECUTESQL
    N'SELECT * FROM dbo.BlaBLa(@P1)',N'@P1 INT',@P1 = 37155


    Resulting in the expected seek predicates



     SQL Server Execution Times:
    CPU time = 0 ms, elapsed time = 0 ms.


    With about 9 logical reads on my test




    Addendum #1



    CREATE TABLE dbo.Codemaster 
    (
    CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
    , ManagerID INT NULL
    , ParentDeptID int NULL
    , SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
    , SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
    , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
    )
    WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Codemaster_History))
    ;

    CREATE TABLE dbo.Deal
    (
    DealID int NOT NULL PRIMARY KEY CLUSTERED
    , CodeMasterID INT NULL
    , EvenMoreBlaID int NULL
    , SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
    , SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
    , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
    )
    WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Deal_History))
    ;

    INSERT INTO dbo.Codemaster(CodeMasterID,ManagerID,ParentDeptID)
    SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
    ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
    ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
    FROM MASTER..spt_values as spt1
    CROSS JOIN MASTER..spt_values as spt2;


    INSERT INTO dbo.Deal(DealID,CodeMasterID,EvenMoreBlaID)
    SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
    ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
    ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
    FROM MASTER..spt_values as spt1
    CROSS JOIN MASTER..spt_values as spt2;

    CREATE INDEX IX_CodeMasterID
    ON dbo.Deal(CodeMasterId);
    CREATE INDEX IX_CodeMasterID
    ON dbo.Deal_History(CodeMasterId);

    CREATE INDEX IX_CodeMasterID
    ON dbo.Codemaster(CodeMasterId);
    CREATE INDEX IX_CodeMasterID
    ON dbo.Codemaster_History(CodeMasterId);


    SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
    cm.*, d.*
    FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
    INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID
    Where cm.CodeMasterID = 37155;

    -- Guud
    GO
    CREATE VIEW dbo.Bad
    as
    SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
    cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
    FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
    INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID

    GO
    EXEC SP_EXECUTESQL
    N'SELECT * FROM dbo.Bad
    Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155

    -- Very bad shame on you



    Addendum #2



    CREATE TABLE dbo.Codemaster2
    (
    CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
    , ManagerID INT NULL
    , ParentDeptID int NULL

    );

    CREATE TABLE dbo.Deal2
    (
    DealID int NOT NULL PRIMARY KEY CLUSTERED
    , CodeMasterID INT NULL
    , EvenMoreBlaID int NULL
    );

    INSERT INTO dbo.Codemaster2(CodeMasterID,ManagerID,ParentDeptID)
    SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
    ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
    ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
    FROM MASTER..spt_values as spt1
    CROSS JOIN MASTER..spt_values as spt2;


    INSERT INTO dbo.Deal2(DealID,CodeMasterID,EvenMoreBlaID)
    SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
    ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
    ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
    FROM MASTER..spt_values as spt1
    CROSS JOIN MASTER..spt_values as spt2;

    CREATE INDEX IX_CodeMasterID
    ON dbo.Deal2(CodeMasterId);
    CREATE INDEX IX_CodeMasterID
    ON dbo.Codemaster2(CodeMasterId);


    SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterId) AS Deal_HistoryID,
    cm.*, d.*
    FROM dbo.CodeMaster2 cm
    INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
    Where cm.CodeMasterID = 37155;

    -- Guud
    GO
    CREATE VIEW dbo.Bad2
    as
    SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
    cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
    FROM dbo.CodeMaster2 cm
    INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID

    GO
    SET STATISTICS IO, TIME ON;
    EXEC SP_EXECUTESQL
    N'SELECT * FROM dbo.Bad2
    Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155





    share|improve this answer





























      5














      The main performance differences



      The main differences here are that the better performing query is pushing down the seek predicate on CodeMasterID on all 4 tables (2 temporal tables (actual & history)) where the select on the view appears to not do that until the end (filter operator).



      TL DR;



      The issue is due to to parameters not pushing down to window functions in certain cases such as views. The easiest solution is adding OPTION(RECOMPILE) to the view call as to make the optimizer 'see' the params at runtime if that is a possibility. If it is too expensive to recompile the execution plan for each query call, using an inline table valued function that expects a parameter could be a solution. There is an excellent Blogpost by Paul White on this. For a more detailed way on finding and resolving your particular issue, keep on reading.



      The better performing query



      Codemaster table



      enter image description here



      enter image description here



      Deal table



      enter image description here



      enter image description here



      I love the smell of seek predicates in the morning




      The big bad query



      Codemaster table



      enter image description here



      enter image description here



      This is a predicate only zone



      The Deal table



      enter image description here



      But the optimizer did not read 'The art of the deal™"



      enter image description here



      ...and does not learn from the past



      Until all that data reaches the filter operator



      enter image description here




      So, what gives?



      The main problem here is the optimizer not 'seeing' the parameters at runtime due to the window functions in the view and not being able to use the SelOnSeqPrj (select on sequence project, further down in this post for reference).



      I was able to replicate the same results with a test sample and using SP_EXECUTESQL to parameterize the call to the view. See addendum for the DDL / DML



      executing a query against a test view with a window function and an INNER JOIN



      SET STATISTICS IO, TIME ON;
      EXEC SP_EXECUTESQL
      N'SELECT * FROM dbo.Bad
      Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155;


      Resulting in about 4.5s of cpu time and 3.2s elapsed time



       SQL Server Execution Times:
      CPU time = 4595 ms, elapsed time = 3209 ms.


      When we add the sweet embrace of OPTION(RECOMPILE)



      SET STATISTICS IO, TIME ON;
      EXEC SP_EXECUTESQL
      N'SELECT * FROM dbo.Bad
      Where CodeMasterID = @P1 OPTION(RECOMPILE)',N'@P1 INT',@P1 = 37155;


      It is all good.



       SQL Server Execution Times:
      CPU time = 16 ms, elapsed time = 98 ms.


      Why



      This all again supports the point of not being able to apply the @P1 predicate to the tables because of the window function & parameterization resulting in the filter operator



      enter image description hereenter image description here



      Not only an issue for temporal tables



      See addendum 2



      Even when not using temporal tables, this happens:
      enter image description here



      The same result is seen when writing the query like this:



      DECLARE @P1 int = 37155
      SELECT * FROM dbo.Bad2
      Where CodeMasterID = @P1;


      Again, the optimizer is not pushing down the predicate before applying the window function.



      When omitting the ROW_NUMBER()



      CREATE VIEW dbo.Bad3
      as
      SELECT
      cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
      FROM dbo.CodeMaster2 cm
      INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID;


      All is well



      SET STATISTICS IO, TIME ON;
      EXEC SP_EXECUTESQL
      N'SELECT * FROM dbo.Bad3
      Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155


      SQL Server Execution Times:
      CPU time = 0 ms, elapsed time = 33 ms.


      so where does all that leave us?



      The ROW_NUMBER() is calculated before the filter is applied on the bad queries.



      And all this leads us to this blogpost from 2013 by Paul White
      on window functions and views.



      One of the important parts for our example is this statement:




      Unfortunately, the SelOnSeqPrj simplification rule only works when the
      predicate performs a comparison with a constant. For that reason, the
      following query produces the sub-optimal plan on SQL Server 2008 and
      later:




      DECLARE @ProductID INT = 878;

      SELECT
      mrt.ProductID,
      mrt.TransactionID,
      mrt.ReferenceOrderID,
      mrt.TransactionDate,
      mrt.Quantity
      FROM dbo.MostRecentTransactionsPerProduct AS mrt
      WHERE
      mrt.ProductID = @ProductID;


      enter image description here



      This part corresponds to what we have seen when declaring the parameter ourselves / using SP_EXECUTESQL on the view.




      The actual solutions



      OPTION(RECOMPILE)


      We know that OPTION(RECOMPILE) to 'see' the value at runtime is a possibility. When recompiling the execution plan for each query call is too expensive, there are other solutions.



      Inline table valued function with a parameter



      CREATE FUNCTION dbo.BlaBla
      (
      @P1 INT
      )
      RETURNS TABLE
      WITH SCHEMABINDING AS
      RETURN
      (
      SELECT
      ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
      cm.CodeMasterID,CM.ManagerID,
      cm.ParentDeptID,d.DealID,
      d.CodeMasterID as dealcodemaster,
      d.EvenMoreBlaID
      FROM dbo.CodeMaster2 cm
      INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
      Where cm.CodeMasterID = @P1
      )
      EXEC SP_EXECUTESQL
      N'SELECT * FROM dbo.BlaBLa(@P1)',N'@P1 INT',@P1 = 37155


      Resulting in the expected seek predicates



       SQL Server Execution Times:
      CPU time = 0 ms, elapsed time = 0 ms.


      With about 9 logical reads on my test




      Addendum #1



      CREATE TABLE dbo.Codemaster 
      (
      CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
      , ManagerID INT NULL
      , ParentDeptID int NULL
      , SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
      , SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
      , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
      )
      WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Codemaster_History))
      ;

      CREATE TABLE dbo.Deal
      (
      DealID int NOT NULL PRIMARY KEY CLUSTERED
      , CodeMasterID INT NULL
      , EvenMoreBlaID int NULL
      , SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
      , SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
      , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
      )
      WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Deal_History))
      ;

      INSERT INTO dbo.Codemaster(CodeMasterID,ManagerID,ParentDeptID)
      SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
      ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
      ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
      FROM MASTER..spt_values as spt1
      CROSS JOIN MASTER..spt_values as spt2;


      INSERT INTO dbo.Deal(DealID,CodeMasterID,EvenMoreBlaID)
      SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
      ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
      ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
      FROM MASTER..spt_values as spt1
      CROSS JOIN MASTER..spt_values as spt2;

      CREATE INDEX IX_CodeMasterID
      ON dbo.Deal(CodeMasterId);
      CREATE INDEX IX_CodeMasterID
      ON dbo.Deal_History(CodeMasterId);

      CREATE INDEX IX_CodeMasterID
      ON dbo.Codemaster(CodeMasterId);
      CREATE INDEX IX_CodeMasterID
      ON dbo.Codemaster_History(CodeMasterId);


      SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
      cm.*, d.*
      FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
      INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID
      Where cm.CodeMasterID = 37155;

      -- Guud
      GO
      CREATE VIEW dbo.Bad
      as
      SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
      cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
      FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
      INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID

      GO
      EXEC SP_EXECUTESQL
      N'SELECT * FROM dbo.Bad
      Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155

      -- Very bad shame on you



      Addendum #2



      CREATE TABLE dbo.Codemaster2
      (
      CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
      , ManagerID INT NULL
      , ParentDeptID int NULL

      );

      CREATE TABLE dbo.Deal2
      (
      DealID int NOT NULL PRIMARY KEY CLUSTERED
      , CodeMasterID INT NULL
      , EvenMoreBlaID int NULL
      );

      INSERT INTO dbo.Codemaster2(CodeMasterID,ManagerID,ParentDeptID)
      SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
      ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
      ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
      FROM MASTER..spt_values as spt1
      CROSS JOIN MASTER..spt_values as spt2;


      INSERT INTO dbo.Deal2(DealID,CodeMasterID,EvenMoreBlaID)
      SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
      ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
      ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
      FROM MASTER..spt_values as spt1
      CROSS JOIN MASTER..spt_values as spt2;

      CREATE INDEX IX_CodeMasterID
      ON dbo.Deal2(CodeMasterId);
      CREATE INDEX IX_CodeMasterID
      ON dbo.Codemaster2(CodeMasterId);


      SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterId) AS Deal_HistoryID,
      cm.*, d.*
      FROM dbo.CodeMaster2 cm
      INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
      Where cm.CodeMasterID = 37155;

      -- Guud
      GO
      CREATE VIEW dbo.Bad2
      as
      SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
      cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
      FROM dbo.CodeMaster2 cm
      INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID

      GO
      SET STATISTICS IO, TIME ON;
      EXEC SP_EXECUTESQL
      N'SELECT * FROM dbo.Bad2
      Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155





      share|improve this answer



























        5












        5








        5







        The main performance differences



        The main differences here are that the better performing query is pushing down the seek predicate on CodeMasterID on all 4 tables (2 temporal tables (actual & history)) where the select on the view appears to not do that until the end (filter operator).



        TL DR;



        The issue is due to to parameters not pushing down to window functions in certain cases such as views. The easiest solution is adding OPTION(RECOMPILE) to the view call as to make the optimizer 'see' the params at runtime if that is a possibility. If it is too expensive to recompile the execution plan for each query call, using an inline table valued function that expects a parameter could be a solution. There is an excellent Blogpost by Paul White on this. For a more detailed way on finding and resolving your particular issue, keep on reading.



        The better performing query



        Codemaster table



        enter image description here



        enter image description here



        Deal table



        enter image description here



        enter image description here



        I love the smell of seek predicates in the morning




        The big bad query



        Codemaster table



        enter image description here



        enter image description here



        This is a predicate only zone



        The Deal table



        enter image description here



        But the optimizer did not read 'The art of the deal™"



        enter image description here



        ...and does not learn from the past



        Until all that data reaches the filter operator



        enter image description here




        So, what gives?



        The main problem here is the optimizer not 'seeing' the parameters at runtime due to the window functions in the view and not being able to use the SelOnSeqPrj (select on sequence project, further down in this post for reference).



        I was able to replicate the same results with a test sample and using SP_EXECUTESQL to parameterize the call to the view. See addendum for the DDL / DML



        executing a query against a test view with a window function and an INNER JOIN



        SET STATISTICS IO, TIME ON;
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad
        Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155;


        Resulting in about 4.5s of cpu time and 3.2s elapsed time



         SQL Server Execution Times:
        CPU time = 4595 ms, elapsed time = 3209 ms.


        When we add the sweet embrace of OPTION(RECOMPILE)



        SET STATISTICS IO, TIME ON;
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad
        Where CodeMasterID = @P1 OPTION(RECOMPILE)',N'@P1 INT',@P1 = 37155;


        It is all good.



         SQL Server Execution Times:
        CPU time = 16 ms, elapsed time = 98 ms.


        Why



        This all again supports the point of not being able to apply the @P1 predicate to the tables because of the window function & parameterization resulting in the filter operator



        enter image description hereenter image description here



        Not only an issue for temporal tables



        See addendum 2



        Even when not using temporal tables, this happens:
        enter image description here



        The same result is seen when writing the query like this:



        DECLARE @P1 int = 37155
        SELECT * FROM dbo.Bad2
        Where CodeMasterID = @P1;


        Again, the optimizer is not pushing down the predicate before applying the window function.



        When omitting the ROW_NUMBER()



        CREATE VIEW dbo.Bad3
        as
        SELECT
        cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
        FROM dbo.CodeMaster2 cm
        INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID;


        All is well



        SET STATISTICS IO, TIME ON;
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad3
        Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155


        SQL Server Execution Times:
        CPU time = 0 ms, elapsed time = 33 ms.


        so where does all that leave us?



        The ROW_NUMBER() is calculated before the filter is applied on the bad queries.



        And all this leads us to this blogpost from 2013 by Paul White
        on window functions and views.



        One of the important parts for our example is this statement:




        Unfortunately, the SelOnSeqPrj simplification rule only works when the
        predicate performs a comparison with a constant. For that reason, the
        following query produces the sub-optimal plan on SQL Server 2008 and
        later:




        DECLARE @ProductID INT = 878;

        SELECT
        mrt.ProductID,
        mrt.TransactionID,
        mrt.ReferenceOrderID,
        mrt.TransactionDate,
        mrt.Quantity
        FROM dbo.MostRecentTransactionsPerProduct AS mrt
        WHERE
        mrt.ProductID = @ProductID;


        enter image description here



        This part corresponds to what we have seen when declaring the parameter ourselves / using SP_EXECUTESQL on the view.




        The actual solutions



        OPTION(RECOMPILE)


        We know that OPTION(RECOMPILE) to 'see' the value at runtime is a possibility. When recompiling the execution plan for each query call is too expensive, there are other solutions.



        Inline table valued function with a parameter



        CREATE FUNCTION dbo.BlaBla
        (
        @P1 INT
        )
        RETURNS TABLE
        WITH SCHEMABINDING AS
        RETURN
        (
        SELECT
        ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
        cm.CodeMasterID,CM.ManagerID,
        cm.ParentDeptID,d.DealID,
        d.CodeMasterID as dealcodemaster,
        d.EvenMoreBlaID
        FROM dbo.CodeMaster2 cm
        INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
        Where cm.CodeMasterID = @P1
        )
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.BlaBLa(@P1)',N'@P1 INT',@P1 = 37155


        Resulting in the expected seek predicates



         SQL Server Execution Times:
        CPU time = 0 ms, elapsed time = 0 ms.


        With about 9 logical reads on my test




        Addendum #1



        CREATE TABLE dbo.Codemaster 
        (
        CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
        , ManagerID INT NULL
        , ParentDeptID int NULL
        , SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
        , SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
        , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
        )
        WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Codemaster_History))
        ;

        CREATE TABLE dbo.Deal
        (
        DealID int NOT NULL PRIMARY KEY CLUSTERED
        , CodeMasterID INT NULL
        , EvenMoreBlaID int NULL
        , SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
        , SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
        , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
        )
        WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Deal_History))
        ;

        INSERT INTO dbo.Codemaster(CodeMasterID,ManagerID,ParentDeptID)
        SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
        FROM MASTER..spt_values as spt1
        CROSS JOIN MASTER..spt_values as spt2;


        INSERT INTO dbo.Deal(DealID,CodeMasterID,EvenMoreBlaID)
        SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
        FROM MASTER..spt_values as spt1
        CROSS JOIN MASTER..spt_values as spt2;

        CREATE INDEX IX_CodeMasterID
        ON dbo.Deal(CodeMasterId);
        CREATE INDEX IX_CodeMasterID
        ON dbo.Deal_History(CodeMasterId);

        CREATE INDEX IX_CodeMasterID
        ON dbo.Codemaster(CodeMasterId);
        CREATE INDEX IX_CodeMasterID
        ON dbo.Codemaster_History(CodeMasterId);


        SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
        cm.*, d.*
        FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
        INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID
        Where cm.CodeMasterID = 37155;

        -- Guud
        GO
        CREATE VIEW dbo.Bad
        as
        SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
        cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
        FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
        INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID

        GO
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad
        Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155

        -- Very bad shame on you



        Addendum #2



        CREATE TABLE dbo.Codemaster2
        (
        CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
        , ManagerID INT NULL
        , ParentDeptID int NULL

        );

        CREATE TABLE dbo.Deal2
        (
        DealID int NOT NULL PRIMARY KEY CLUSTERED
        , CodeMasterID INT NULL
        , EvenMoreBlaID int NULL
        );

        INSERT INTO dbo.Codemaster2(CodeMasterID,ManagerID,ParentDeptID)
        SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
        FROM MASTER..spt_values as spt1
        CROSS JOIN MASTER..spt_values as spt2;


        INSERT INTO dbo.Deal2(DealID,CodeMasterID,EvenMoreBlaID)
        SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
        FROM MASTER..spt_values as spt1
        CROSS JOIN MASTER..spt_values as spt2;

        CREATE INDEX IX_CodeMasterID
        ON dbo.Deal2(CodeMasterId);
        CREATE INDEX IX_CodeMasterID
        ON dbo.Codemaster2(CodeMasterId);


        SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterId) AS Deal_HistoryID,
        cm.*, d.*
        FROM dbo.CodeMaster2 cm
        INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
        Where cm.CodeMasterID = 37155;

        -- Guud
        GO
        CREATE VIEW dbo.Bad2
        as
        SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
        cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
        FROM dbo.CodeMaster2 cm
        INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID

        GO
        SET STATISTICS IO, TIME ON;
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad2
        Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155





        share|improve this answer















        The main performance differences



        The main differences here are that the better performing query is pushing down the seek predicate on CodeMasterID on all 4 tables (2 temporal tables (actual & history)) where the select on the view appears to not do that until the end (filter operator).



        TL DR;



        The issue is due to to parameters not pushing down to window functions in certain cases such as views. The easiest solution is adding OPTION(RECOMPILE) to the view call as to make the optimizer 'see' the params at runtime if that is a possibility. If it is too expensive to recompile the execution plan for each query call, using an inline table valued function that expects a parameter could be a solution. There is an excellent Blogpost by Paul White on this. For a more detailed way on finding and resolving your particular issue, keep on reading.



        The better performing query



        Codemaster table



        enter image description here



        enter image description here



        Deal table



        enter image description here



        enter image description here



        I love the smell of seek predicates in the morning




        The big bad query



        Codemaster table



        enter image description here



        enter image description here



        This is a predicate only zone



        The Deal table



        enter image description here



        But the optimizer did not read 'The art of the deal™"



        enter image description here



        ...and does not learn from the past



        Until all that data reaches the filter operator



        enter image description here




        So, what gives?



        The main problem here is the optimizer not 'seeing' the parameters at runtime due to the window functions in the view and not being able to use the SelOnSeqPrj (select on sequence project, further down in this post for reference).



        I was able to replicate the same results with a test sample and using SP_EXECUTESQL to parameterize the call to the view. See addendum for the DDL / DML



        executing a query against a test view with a window function and an INNER JOIN



        SET STATISTICS IO, TIME ON;
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad
        Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155;


        Resulting in about 4.5s of cpu time and 3.2s elapsed time



         SQL Server Execution Times:
        CPU time = 4595 ms, elapsed time = 3209 ms.


        When we add the sweet embrace of OPTION(RECOMPILE)



        SET STATISTICS IO, TIME ON;
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad
        Where CodeMasterID = @P1 OPTION(RECOMPILE)',N'@P1 INT',@P1 = 37155;


        It is all good.



         SQL Server Execution Times:
        CPU time = 16 ms, elapsed time = 98 ms.


        Why



        This all again supports the point of not being able to apply the @P1 predicate to the tables because of the window function & parameterization resulting in the filter operator



        enter image description hereenter image description here



        Not only an issue for temporal tables



        See addendum 2



        Even when not using temporal tables, this happens:
        enter image description here



        The same result is seen when writing the query like this:



        DECLARE @P1 int = 37155
        SELECT * FROM dbo.Bad2
        Where CodeMasterID = @P1;


        Again, the optimizer is not pushing down the predicate before applying the window function.



        When omitting the ROW_NUMBER()



        CREATE VIEW dbo.Bad3
        as
        SELECT
        cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
        FROM dbo.CodeMaster2 cm
        INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID;


        All is well



        SET STATISTICS IO, TIME ON;
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad3
        Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155


        SQL Server Execution Times:
        CPU time = 0 ms, elapsed time = 33 ms.


        so where does all that leave us?



        The ROW_NUMBER() is calculated before the filter is applied on the bad queries.



        And all this leads us to this blogpost from 2013 by Paul White
        on window functions and views.



        One of the important parts for our example is this statement:




        Unfortunately, the SelOnSeqPrj simplification rule only works when the
        predicate performs a comparison with a constant. For that reason, the
        following query produces the sub-optimal plan on SQL Server 2008 and
        later:




        DECLARE @ProductID INT = 878;

        SELECT
        mrt.ProductID,
        mrt.TransactionID,
        mrt.ReferenceOrderID,
        mrt.TransactionDate,
        mrt.Quantity
        FROM dbo.MostRecentTransactionsPerProduct AS mrt
        WHERE
        mrt.ProductID = @ProductID;


        enter image description here



        This part corresponds to what we have seen when declaring the parameter ourselves / using SP_EXECUTESQL on the view.




        The actual solutions



        OPTION(RECOMPILE)


        We know that OPTION(RECOMPILE) to 'see' the value at runtime is a possibility. When recompiling the execution plan for each query call is too expensive, there are other solutions.



        Inline table valued function with a parameter



        CREATE FUNCTION dbo.BlaBla
        (
        @P1 INT
        )
        RETURNS TABLE
        WITH SCHEMABINDING AS
        RETURN
        (
        SELECT
        ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
        cm.CodeMasterID,CM.ManagerID,
        cm.ParentDeptID,d.DealID,
        d.CodeMasterID as dealcodemaster,
        d.EvenMoreBlaID
        FROM dbo.CodeMaster2 cm
        INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
        Where cm.CodeMasterID = @P1
        )
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.BlaBLa(@P1)',N'@P1 INT',@P1 = 37155


        Resulting in the expected seek predicates



         SQL Server Execution Times:
        CPU time = 0 ms, elapsed time = 0 ms.


        With about 9 logical reads on my test




        Addendum #1



        CREATE TABLE dbo.Codemaster 
        (
        CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
        , ManagerID INT NULL
        , ParentDeptID int NULL
        , SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
        , SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
        , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
        )
        WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Codemaster_History))
        ;

        CREATE TABLE dbo.Deal
        (
        DealID int NOT NULL PRIMARY KEY CLUSTERED
        , CodeMasterID INT NULL
        , EvenMoreBlaID int NULL
        , SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL
        , SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL
        , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime)
        )
        WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Deal_History))
        ;

        INSERT INTO dbo.Codemaster(CodeMasterID,ManagerID,ParentDeptID)
        SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
        FROM MASTER..spt_values as spt1
        CROSS JOIN MASTER..spt_values as spt2;


        INSERT INTO dbo.Deal(DealID,CodeMasterID,EvenMoreBlaID)
        SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
        FROM MASTER..spt_values as spt1
        CROSS JOIN MASTER..spt_values as spt2;

        CREATE INDEX IX_CodeMasterID
        ON dbo.Deal(CodeMasterId);
        CREATE INDEX IX_CodeMasterID
        ON dbo.Deal_History(CodeMasterId);

        CREATE INDEX IX_CodeMasterID
        ON dbo.Codemaster(CodeMasterId);
        CREATE INDEX IX_CodeMasterID
        ON dbo.Codemaster_History(CodeMasterId);


        SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
        cm.*, d.*
        FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
        INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID
        Where cm.CodeMasterID = 37155;

        -- Guud
        GO
        CREATE VIEW dbo.Bad
        as
        SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID, cm.SysStartTime) AS Deal_HistoryID,
        cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
        FROM dbo.CodeMaster FOR SYSTEM_TIME ALL cm
        INNER JOIN dbo.Deal FOR SYSTEM_TIME ALL d ON cm.CodeMasterID = d.CodeMasterID

        GO
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad
        Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155

        -- Very bad shame on you



        Addendum #2



        CREATE TABLE dbo.Codemaster2
        (
        CodeMasterID int NOT NULL PRIMARY KEY CLUSTERED
        , ManagerID INT NULL
        , ParentDeptID int NULL

        );

        CREATE TABLE dbo.Deal2
        (
        DealID int NOT NULL PRIMARY KEY CLUSTERED
        , CodeMasterID INT NULL
        , EvenMoreBlaID int NULL
        );

        INSERT INTO dbo.Codemaster2(CodeMasterID,ManagerID,ParentDeptID)
        SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
        FROM MASTER..spt_values as spt1
        CROSS JOIN MASTER..spt_values as spt2;


        INSERT INTO dbo.Deal2(DealID,CodeMasterID,EvenMoreBlaID)
        SELECT TOP(1000000) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum1,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum2,
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) as rownum3
        FROM MASTER..spt_values as spt1
        CROSS JOIN MASTER..spt_values as spt2;

        CREATE INDEX IX_CodeMasterID
        ON dbo.Deal2(CodeMasterId);
        CREATE INDEX IX_CodeMasterID
        ON dbo.Codemaster2(CodeMasterId);


        SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterId) AS Deal_HistoryID,
        cm.*, d.*
        FROM dbo.CodeMaster2 cm
        INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID
        Where cm.CodeMasterID = 37155;

        -- Guud
        GO
        CREATE VIEW dbo.Bad2
        as
        SELECT ROW_NUMBER() OVER (PARTITION BY cm.CodeMasterID ORDER BY cm.CodeMasterID) AS Deal_HistoryID,
        cm.CodeMasterID,CM.ManagerID,cm.ParentDeptID,d.DealID, d.CodeMasterID as dealcodemaster,d.EvenMoreBlaID
        FROM dbo.CodeMaster2 cm
        INNER JOIN dbo.Deal2 d ON cm.CodeMasterID = d.CodeMasterID

        GO
        SET STATISTICS IO, TIME ON;
        EXEC SP_EXECUTESQL
        N'SELECT * FROM dbo.Bad2
        Where CodeMasterID = @P1',N'@P1 INT',@P1 = 37155






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 3 hours ago

























        answered 4 hours ago









        Randi VertongenRandi Vertongen

        5,9312928




        5,9312928



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Database Administrators Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f239370%2fselect-from-view-takes-4-minutes%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            ParseJSON using SSJSUsing AMPscript with SSJS ActivitiesHow to resubscribe a user in Marketing cloud using SSJS?Pulling Subscriber Status from Lists using SSJSRetrieving Emails using SSJSProblem in updating DE using SSJSUsing SSJS to send single email in Marketing CloudError adding EmailSendDefinition using SSJS

            Кампала Садржај Географија Географија Историја Становништво Привреда Партнерски градови Референце Спољашње везе Мени за навигацију0°11′ СГШ; 32°20′ ИГД / 0.18° СГШ; 32.34° ИГД / 0.18; 32.340°11′ СГШ; 32°20′ ИГД / 0.18° СГШ; 32.34° ИГД / 0.18; 32.34МедијиПодациЗванични веб-сајту

            19. јануар Садржај Догађаји Рођења Смрти Празници и дани сећања Види још Референце Мени за навигацијуу