Inside the SQL Server Query Optimizer - part 6 What is the memo?

Hi Guys,

Where did we get to last time?

Last time we had talked about the cost based optimization process and the transformation rules that applied by the optimizer were looking for a better performance plan.

The memo

So the question is: Where our alternative plans are stored?
They are stored in a component called memo.

You can find more info about this structure in the “Cascades general optimization framework” developed by Goetz Graefe.

Today I would show you only how the memo work, nothing more!
We should enable some trace flag in order to display the information we need.
  • Through the trace flag 8608 we can show the initial Memo Structure,
  • Through the trace flag 8615 we can show the final Memo Structure,

To better explain the process we take as example our Query used in the previous posts.
       
SELECT
  ANNDOC, NUMDOC, SUM(R.QTA1) AS SUM_QTA
FROM ORDTES T
  JOIN ORDRIG R ON R.IDORDTES = T.ID
WHERE
  ANNDOC = 2018 
GROUP BY ANNDOC, NUMDOC
ORDER BY ANNDOC, NUMDOC
OPTION ( RECOMPILE,
          querytraceon 2363,
          querytraceon 3604,
          querytraceon 8606,  -- race flag 8606 will display additional logical trees used during the optimization process
          querytraceon 8612,  -- Add Extra Info to the Trees Output
          querytraceon 8619,  -- Show Applied Transformation Rules
          querytraceon 8620,  -- 8620 = Add memo arguments to trace flag 8619
          querytraceon 8608,  -- Shows the initial Memo structure
          querytraceon 8615,  -- Display the final memo structure
          querytraceon 8621)  -- 8621 = Rule with resulting tree


As seen in the previous post our query have this logical tree:





Through the flag 8608 we can take a look to the initial Memo Structure.

You can note, at this point, that the logical tree is simply copied into the memo.
One group per logical node.

       

 ****************************************
--- Initial Memo Structure ---

Root Group 14: Card=1635.67 (Max=8.4478e+010, Min=0)

   0 LogOp_GbAgg 9 13 (Distance = 0)


Group 13:
   0 AncOp_PrjList  12 (Distance = 0)


Group 12:
   0 AncOp_PrjEl  11 (Distance = 0)


Group 11:
   0 ScaOp_AggFunc  10 (Distance = 0)


Group 10:
   0 ScaOp_Identifier  (Distance = 0)


Group 9: Card=66408.4 (Max=8.4478e+010, Min=0)

   0 LogOp_Join 4 5 8 (Distance = 0)


Group 8:
   0 ScaOp_Comp  6 7 (Distance = 0)


Group 7:
   0 ScaOp_Identifier  (Distance = 0)


Group 6:
   0 ScaOp_Identifier  (Distance = 0)



Group 5: Card=566688 (Max=623357, Min=0)

   0 LogOp_Get (Distance = 0)


Group 4: Card=1641 (Max=135521, Min=0)

   0 LogOp_Select 0 3 (Distance = 0)


Group 3:
   0 ScaOp_Comp  1 2 (Distance = 0)


Group 2:
   0 ScaOp_Const  (Distance = 0)


Group 1:
   0 ScaOp_Identifier  (Distance = 0)


Group 0: Card=123201 (Max=135521, Min=0)

   0 LogOp_Get (Distance = 0)



Now at the end of the optimization procedure (so after the Search 0, Search 1 and Search 2 phases of witch we speak in detail in the next and last post of this series) we will have in the memo all the optimization applied.

Here our final Memo Structure after the Search optimization phases:

Remember: Each phases can add a new group or an existing group may be expanded to include other logical and physical alternative.

       

--- Final Memo Structure ---

Group 32: Card=566688 (Max=623357, Min=0)

   0 LogOp_Spool 5 (Distance = 1)



Group 31: Card=46607.6 (Max=623357, Min=0)

   0 LogOp_Spool 22 (Distance = 3)



Group 30: Card=1 (Max=135521, Min=0)

   0 LogOp_SelectRes 29 3 (Distance = 4)



Group 29: Card=1 (Max=135521, Min=0)

   0 LogOp_SelectIdx 28 8 (Distance = 4)



Group 28: Card=123201 (Max=135521, Min=0)

   0 LogOp_GetIdx (Distance = 4)



Group 27: Card=1 (Max=135521, Min=0)

   1 PhyOp_Range 5 ASC  26.0  Cost(RowGoal 0,ReW 0.0512361,ReB 46606.6,Dist 46607.6,Total 46607.6)= 7.37882 (Distance = 5)


   0 LogOp_SelectIdx 25 26 (Distance = 4)



Group 26:
   0 ScaOp_Logical  8.0 3.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 7 (Distance = 4)



Group 25: Card=123201 (Max=135521, Min=0)

   0 LogOp_GetIdx (Distance = 4)



Group 24: Card=566688 (Max=623357, Min=0)

   1 PhyOp_Range 1 ASC   Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 26.8615 (Distance = 2)


   0 LogOp_GetIdx (Distance = 1)



Group 23: Card=1641 (Max=135521, Min=0)

   3 PhyOp_HashJoinx_jtInner 4.1 22.1 8.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 32.1464 (Distance = 3)


   2 PhyOp_Sort 23.3  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 32.1851 (Distance = 0)


   1 LogOp_Join 22 4 8 (Distance = 3)


   0 LogOp_Join 4 22 8 (Distance = 2)



Group 22: Card=46607.6 (Max=623357, Min=0)

   6 PhyOp_Sort 22.1  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 35.1172 (Distance = 0)


   1 PhyOp_HashGbAgg 5.2 16.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 31.7882 (Distance = 3)


   0 LogOp_GbAgg 5 16 (Distance = 2)



Group 21:
   0 AncOp_PrjList  20.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 0 (Distance = 1)



Group 20:
   0 AncOp_PrjEl  19.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 0 (Distance = 1)



Group 19:
   0 ScaOp_AggFunc  18.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 2 (Distance = 1)



Group 18:
   0 ScaOp_Identifier   Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 1 (Distance = 1)



Group 17: Card=6542.61 (Max=8.4478e+010, Min=0)

   2 PhyOp_HashGbAgg 9.2 16.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 31.1182 (Distance = 2)


   1 PhyOp_Sort 17.2  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 31.3337 (Distance = 0)


   0 LogOp_GbAgg 9 16 (Distance = 1)



Group 16:
   0 AncOp_PrjList  15.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 0 (Distance = 1)



Group 15:
   0 AncOp_PrjEl  11.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 0 (Distance = 1)



Root Group 14: Card=1635.67 (Max=8.4478e+010, Min=0)

   11 PhyOp_HashGbAgg 9.2 13.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 31.0412 (Distance = 1)


   9 PhyOp_Sort 14.11  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 31.0798 (Distance = 0)


   2 LogOp_GbAgg 23 21 (Distance = 2)


   1 LogOp_GbAgg 17 21 (Distance = 1)


   0 LogOp_GbAgg 9 13 (Distance = 0)



Group 13:
   0 AncOp_PrjList  12.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 0 (Distance = 0)



Group 12:
   0 AncOp_PrjEl  11.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 0 (Distance = 0)



Group 11:
   0 ScaOp_AggFunc  10.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 2 (Distance = 0)



Group 10:
   0 ScaOp_Identifier   Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 1 (Distance = 0)



Group 9: Card=66408.4 (Max=8.4478e+010, Min=0)

   8 PhyOp_Sort 9.2  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 35.5838 (Distance = 0)


   2 PhyOp_HashJoinx_jtInner 4.1 5.2 8.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 30.6896 (Distance = 1)


   1 LogOp_Join 5 4 8 (Distance = 1)


   0 LogOp_Join 4 5 8 (Distance = 0)



Group 8:
   0 ScaOp_Comp  6.0 7.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 3 (Distance = 0)



Group 7:
   0 ScaOp_Identifier   Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 1 (Distance = 0)



Group 6:
   0 ScaOp_Identifier   Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 1 (Distance = 0)



Group 5: Card=566688 (Max=623357, Min=0)

   6 PhyOp_Sort 5.2  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 76.5855 (Distance = 0)


   2 PhyOp_Range 1 ASC   Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 26.8615 (Distance = 1)


   0 LogOp_Get (Distance = 0)



Group 4: Card=1641 (Max=135521, Min=0)

   1 PhyOp_Range 5 ASC  3.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 0.00675377 (Distance = 1)


   0 LogOp_Select 0 3 (Distance = 0)



Group 3:
   0 ScaOp_Comp  1.0 2.0  Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 3 (Distance = 0)



Group 2:
   0 ScaOp_Const   Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 1 (Distance = 0)



Group 1:
   0 ScaOp_Identifier   Cost(RowGoal 0,ReW 0,ReB 0,Dist 0,Total 0)= 1 (Distance = 0)



Group 0: Card=123201 (Max=135521, Min=0)

   0 LogOp_Get (Distance = 0)

       
 

That's all for today.
I hope you enjoyed this post! if so wait for the last post of this series!
Have an amazing week!
See you soon!


Luca Biondi @ SQLServerPerformance blog!

Comments

I Post più popolari

SQL Server, execution plan and the lazy spool (clearly explained)

SQL Server, datetime vs. datetime2

La clausola NOLOCK. Approfondiamo e facciamo chiarezza!