Caching intermediary CTEs for multiple uses

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





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







up vote
1
down vote

favorite












I'm working on this huge query that I chose to use CTEs. Due to the complexity of this query, I ended up having to reuse intermediary query results more than once in subsequent queries. The problem I'm facing can be summarized by the following toy code:



WITH cte1 AS (
SELECT id, name
FROM Manager)
, cte2 AS (
SELECT id, name
FROM Employee
LEFT OUTER JOIN cte1 ON Employee.id = cte1.id)
SELECT *
FROM cte1


I have notice an unusual amount of indexes seeks in a fairly small table that was being queried in one the first queries which, according to the execution plan, were taking about 30% of the whole query. This led to me believe the base table was being queried multiple times as it was being referenced more than once in subsequent queries.



I was under the impression that intermediary results in a CTE were cached until the final statement. Reading Microsofts docs on CTEs, I couldn't find any reason to think otherwise.



Are intermediary CTEs cached for muliple uses within an WITH statement? If not, is there a way to cache it without rewriting the query?



Thanks!










share|improve this question

















  • 4




    No there is no way to cache a CTE, it may be executed multiple times if it is referenced multiple times. Use a #temp table instead.
    – Aaron Bertrand♦
    2 hours ago










  • @AaronBertrand, oh, bummer. I was hoping to keep everything within one single WITH statement. But it seems it wouldn't be best choice. Anyway, thanks for the answer and the suggestion.
    – Luís Gabriel de Andrade
    2 hours ago











  • @jean, I'm not using recursive CTEs here. Some CTEs are being referenced more than once but none of them are recursive.
    – Luís Gabriel de Andrade
    2 hours ago










  • @AaronBertrand, as a follow-up, when you say "it may be executed multiple times if it is referenced multiple times" do you mean that there are some instances where SQL Server will cache the queried results? If so, could you give me an example of one of these instances? Thanks!
    – Luís Gabriel de Andrade
    1 hour ago










  • I don't think I suggested it would ever be cached. What I meant was that in some cases the execution plan may be simple enough that the CTE is only materialized once. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case.
    – Aaron Bertrand♦
    1 hour ago
















up vote
1
down vote

favorite












I'm working on this huge query that I chose to use CTEs. Due to the complexity of this query, I ended up having to reuse intermediary query results more than once in subsequent queries. The problem I'm facing can be summarized by the following toy code:



WITH cte1 AS (
SELECT id, name
FROM Manager)
, cte2 AS (
SELECT id, name
FROM Employee
LEFT OUTER JOIN cte1 ON Employee.id = cte1.id)
SELECT *
FROM cte1


I have notice an unusual amount of indexes seeks in a fairly small table that was being queried in one the first queries which, according to the execution plan, were taking about 30% of the whole query. This led to me believe the base table was being queried multiple times as it was being referenced more than once in subsequent queries.



I was under the impression that intermediary results in a CTE were cached until the final statement. Reading Microsofts docs on CTEs, I couldn't find any reason to think otherwise.



Are intermediary CTEs cached for muliple uses within an WITH statement? If not, is there a way to cache it without rewriting the query?



Thanks!










share|improve this question

















  • 4




    No there is no way to cache a CTE, it may be executed multiple times if it is referenced multiple times. Use a #temp table instead.
    – Aaron Bertrand♦
    2 hours ago










  • @AaronBertrand, oh, bummer. I was hoping to keep everything within one single WITH statement. But it seems it wouldn't be best choice. Anyway, thanks for the answer and the suggestion.
    – Luís Gabriel de Andrade
    2 hours ago











  • @jean, I'm not using recursive CTEs here. Some CTEs are being referenced more than once but none of them are recursive.
    – Luís Gabriel de Andrade
    2 hours ago










  • @AaronBertrand, as a follow-up, when you say "it may be executed multiple times if it is referenced multiple times" do you mean that there are some instances where SQL Server will cache the queried results? If so, could you give me an example of one of these instances? Thanks!
    – Luís Gabriel de Andrade
    1 hour ago










  • I don't think I suggested it would ever be cached. What I meant was that in some cases the execution plan may be simple enough that the CTE is only materialized once. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case.
    – Aaron Bertrand♦
    1 hour ago












up vote
1
down vote

favorite









up vote
1
down vote

favorite











I'm working on this huge query that I chose to use CTEs. Due to the complexity of this query, I ended up having to reuse intermediary query results more than once in subsequent queries. The problem I'm facing can be summarized by the following toy code:



WITH cte1 AS (
SELECT id, name
FROM Manager)
, cte2 AS (
SELECT id, name
FROM Employee
LEFT OUTER JOIN cte1 ON Employee.id = cte1.id)
SELECT *
FROM cte1


I have notice an unusual amount of indexes seeks in a fairly small table that was being queried in one the first queries which, according to the execution plan, were taking about 30% of the whole query. This led to me believe the base table was being queried multiple times as it was being referenced more than once in subsequent queries.



I was under the impression that intermediary results in a CTE were cached until the final statement. Reading Microsofts docs on CTEs, I couldn't find any reason to think otherwise.



Are intermediary CTEs cached for muliple uses within an WITH statement? If not, is there a way to cache it without rewriting the query?



Thanks!










share|improve this question













I'm working on this huge query that I chose to use CTEs. Due to the complexity of this query, I ended up having to reuse intermediary query results more than once in subsequent queries. The problem I'm facing can be summarized by the following toy code:



WITH cte1 AS (
SELECT id, name
FROM Manager)
, cte2 AS (
SELECT id, name
FROM Employee
LEFT OUTER JOIN cte1 ON Employee.id = cte1.id)
SELECT *
FROM cte1


I have notice an unusual amount of indexes seeks in a fairly small table that was being queried in one the first queries which, according to the execution plan, were taking about 30% of the whole query. This led to me believe the base table was being queried multiple times as it was being referenced more than once in subsequent queries.



I was under the impression that intermediary results in a CTE were cached until the final statement. Reading Microsofts docs on CTEs, I couldn't find any reason to think otherwise.



Are intermediary CTEs cached for muliple uses within an WITH statement? If not, is there a way to cache it without rewriting the query?



Thanks!







sql-server cte






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 2 hours ago









Luís Gabriel de Andrade

706




706







  • 4




    No there is no way to cache a CTE, it may be executed multiple times if it is referenced multiple times. Use a #temp table instead.
    – Aaron Bertrand♦
    2 hours ago










  • @AaronBertrand, oh, bummer. I was hoping to keep everything within one single WITH statement. But it seems it wouldn't be best choice. Anyway, thanks for the answer and the suggestion.
    – Luís Gabriel de Andrade
    2 hours ago











  • @jean, I'm not using recursive CTEs here. Some CTEs are being referenced more than once but none of them are recursive.
    – Luís Gabriel de Andrade
    2 hours ago










  • @AaronBertrand, as a follow-up, when you say "it may be executed multiple times if it is referenced multiple times" do you mean that there are some instances where SQL Server will cache the queried results? If so, could you give me an example of one of these instances? Thanks!
    – Luís Gabriel de Andrade
    1 hour ago










  • I don't think I suggested it would ever be cached. What I meant was that in some cases the execution plan may be simple enough that the CTE is only materialized once. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case.
    – Aaron Bertrand♦
    1 hour ago












  • 4




    No there is no way to cache a CTE, it may be executed multiple times if it is referenced multiple times. Use a #temp table instead.
    – Aaron Bertrand♦
    2 hours ago










  • @AaronBertrand, oh, bummer. I was hoping to keep everything within one single WITH statement. But it seems it wouldn't be best choice. Anyway, thanks for the answer and the suggestion.
    – Luís Gabriel de Andrade
    2 hours ago











  • @jean, I'm not using recursive CTEs here. Some CTEs are being referenced more than once but none of them are recursive.
    – Luís Gabriel de Andrade
    2 hours ago










  • @AaronBertrand, as a follow-up, when you say "it may be executed multiple times if it is referenced multiple times" do you mean that there are some instances where SQL Server will cache the queried results? If so, could you give me an example of one of these instances? Thanks!
    – Luís Gabriel de Andrade
    1 hour ago










  • I don't think I suggested it would ever be cached. What I meant was that in some cases the execution plan may be simple enough that the CTE is only materialized once. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case.
    – Aaron Bertrand♦
    1 hour ago







4




4




No there is no way to cache a CTE, it may be executed multiple times if it is referenced multiple times. Use a #temp table instead.
– Aaron Bertrand♦
2 hours ago




No there is no way to cache a CTE, it may be executed multiple times if it is referenced multiple times. Use a #temp table instead.
– Aaron Bertrand♦
2 hours ago












@AaronBertrand, oh, bummer. I was hoping to keep everything within one single WITH statement. But it seems it wouldn't be best choice. Anyway, thanks for the answer and the suggestion.
– Luís Gabriel de Andrade
2 hours ago





@AaronBertrand, oh, bummer. I was hoping to keep everything within one single WITH statement. But it seems it wouldn't be best choice. Anyway, thanks for the answer and the suggestion.
– Luís Gabriel de Andrade
2 hours ago













@jean, I'm not using recursive CTEs here. Some CTEs are being referenced more than once but none of them are recursive.
– Luís Gabriel de Andrade
2 hours ago




@jean, I'm not using recursive CTEs here. Some CTEs are being referenced more than once but none of them are recursive.
– Luís Gabriel de Andrade
2 hours ago












@AaronBertrand, as a follow-up, when you say "it may be executed multiple times if it is referenced multiple times" do you mean that there are some instances where SQL Server will cache the queried results? If so, could you give me an example of one of these instances? Thanks!
– Luís Gabriel de Andrade
1 hour ago




@AaronBertrand, as a follow-up, when you say "it may be executed multiple times if it is referenced multiple times" do you mean that there are some instances where SQL Server will cache the queried results? If so, could you give me an example of one of these instances? Thanks!
– Luís Gabriel de Andrade
1 hour ago












I don't think I suggested it would ever be cached. What I meant was that in some cases the execution plan may be simple enough that the CTE is only materialized once. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case.
– Aaron Bertrand♦
1 hour ago




I don't think I suggested it would ever be cached. What I meant was that in some cases the execution plan may be simple enough that the CTE is only materialized once. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case.
– Aaron Bertrand♦
1 hour ago










2 Answers
2






active

oldest

votes

















up vote
3
down vote



accepted










No, there is no way to cache a CTE; it will typically be executed multiple times if it is referenced multiple times. If you want to avoid this, you can cache the results using a #temp table instead.



In some cases, the execution plan may be simple enough that the CTE is only materialized once (this doesn't technically mean it was "cached"), or for the results to be reused with a spool. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case. Even something as simple as this:



CREATE TABLE dbo.OneTuple(id int PRIMARY KEY);
INSERT dbo.OneTuple(id) VALUES(1);
GO

;WITH cte AS
(
SELECT id FROM dbo.OneTuple
)
SELECT id FROM cte
UNION ALL
SELECT id FROM cte;


Yields two identical index scans:




enter image description here




Also see this great Martin Smith answer on Stack Overflow and it is discussed on this feedback item.






share|improve this answer





























    up vote
    1
    down vote













    CTEs are just inline views, which, aside from the functionality provided by recursive CTEs, are nothing more than a syntactic convenience.



    If you need to cache the results of a CTE for multiple subsequent uses, then the best option is to break up the query and load the CTE query's results into a temp table, index it as needed, and then use the temp table in the later queries.






    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',
      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%2f221791%2fcaching-intermediary-ctes-for-multiple-uses%23new-answer', 'question_page');

      );

      Post as a guest






























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      3
      down vote



      accepted










      No, there is no way to cache a CTE; it will typically be executed multiple times if it is referenced multiple times. If you want to avoid this, you can cache the results using a #temp table instead.



      In some cases, the execution plan may be simple enough that the CTE is only materialized once (this doesn't technically mean it was "cached"), or for the results to be reused with a spool. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case. Even something as simple as this:



      CREATE TABLE dbo.OneTuple(id int PRIMARY KEY);
      INSERT dbo.OneTuple(id) VALUES(1);
      GO

      ;WITH cte AS
      (
      SELECT id FROM dbo.OneTuple
      )
      SELECT id FROM cte
      UNION ALL
      SELECT id FROM cte;


      Yields two identical index scans:




      enter image description here




      Also see this great Martin Smith answer on Stack Overflow and it is discussed on this feedback item.






      share|improve this answer


























        up vote
        3
        down vote



        accepted










        No, there is no way to cache a CTE; it will typically be executed multiple times if it is referenced multiple times. If you want to avoid this, you can cache the results using a #temp table instead.



        In some cases, the execution plan may be simple enough that the CTE is only materialized once (this doesn't technically mean it was "cached"), or for the results to be reused with a spool. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case. Even something as simple as this:



        CREATE TABLE dbo.OneTuple(id int PRIMARY KEY);
        INSERT dbo.OneTuple(id) VALUES(1);
        GO

        ;WITH cte AS
        (
        SELECT id FROM dbo.OneTuple
        )
        SELECT id FROM cte
        UNION ALL
        SELECT id FROM cte;


        Yields two identical index scans:




        enter image description here




        Also see this great Martin Smith answer on Stack Overflow and it is discussed on this feedback item.






        share|improve this answer
























          up vote
          3
          down vote



          accepted







          up vote
          3
          down vote



          accepted






          No, there is no way to cache a CTE; it will typically be executed multiple times if it is referenced multiple times. If you want to avoid this, you can cache the results using a #temp table instead.



          In some cases, the execution plan may be simple enough that the CTE is only materialized once (this doesn't technically mean it was "cached"), or for the results to be reused with a spool. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case. Even something as simple as this:



          CREATE TABLE dbo.OneTuple(id int PRIMARY KEY);
          INSERT dbo.OneTuple(id) VALUES(1);
          GO

          ;WITH cte AS
          (
          SELECT id FROM dbo.OneTuple
          )
          SELECT id FROM cte
          UNION ALL
          SELECT id FROM cte;


          Yields two identical index scans:




          enter image description here




          Also see this great Martin Smith answer on Stack Overflow and it is discussed on this feedback item.






          share|improve this answer














          No, there is no way to cache a CTE; it will typically be executed multiple times if it is referenced multiple times. If you want to avoid this, you can cache the results using a #temp table instead.



          In some cases, the execution plan may be simple enough that the CTE is only materialized once (this doesn't technically mean it was "cached"), or for the results to be reused with a spool. I don't have any examples at hand and, even if I did, you couldn't rely on that to always be the case. Even something as simple as this:



          CREATE TABLE dbo.OneTuple(id int PRIMARY KEY);
          INSERT dbo.OneTuple(id) VALUES(1);
          GO

          ;WITH cte AS
          (
          SELECT id FROM dbo.OneTuple
          )
          SELECT id FROM cte
          UNION ALL
          SELECT id FROM cte;


          Yields two identical index scans:




          enter image description here




          Also see this great Martin Smith answer on Stack Overflow and it is discussed on this feedback item.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 19 mins ago

























          answered 50 mins ago









          Aaron Bertrand♦

          147k18279475




          147k18279475






















              up vote
              1
              down vote













              CTEs are just inline views, which, aside from the functionality provided by recursive CTEs, are nothing more than a syntactic convenience.



              If you need to cache the results of a CTE for multiple subsequent uses, then the best option is to break up the query and load the CTE query's results into a temp table, index it as needed, and then use the temp table in the later queries.






              share|improve this answer
























                up vote
                1
                down vote













                CTEs are just inline views, which, aside from the functionality provided by recursive CTEs, are nothing more than a syntactic convenience.



                If you need to cache the results of a CTE for multiple subsequent uses, then the best option is to break up the query and load the CTE query's results into a temp table, index it as needed, and then use the temp table in the later queries.






                share|improve this answer






















                  up vote
                  1
                  down vote










                  up vote
                  1
                  down vote









                  CTEs are just inline views, which, aside from the functionality provided by recursive CTEs, are nothing more than a syntactic convenience.



                  If you need to cache the results of a CTE for multiple subsequent uses, then the best option is to break up the query and load the CTE query's results into a temp table, index it as needed, and then use the temp table in the later queries.






                  share|improve this answer












                  CTEs are just inline views, which, aside from the functionality provided by recursive CTEs, are nothing more than a syntactic convenience.



                  If you need to cache the results of a CTE for multiple subsequent uses, then the best option is to break up the query and load the CTE query's results into a temp table, index it as needed, and then use the temp table in the later queries.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 13 mins ago









                  db2

                  7,85812347




                  7,85812347



























                       

                      draft saved


                      draft discarded















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f221791%2fcaching-intermediary-ctes-for-multiple-uses%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Comments

                      Popular posts from this blog

                      What does second last employer means? [closed]

                      List of Gilmore Girls characters

                      Confectionery