{"id":329,"date":"2018-04-16T14:43:20","date_gmt":"2018-04-16T14:43:20","guid":{"rendered":"https:\/\/www.spotonoracle.com\/?p=329"},"modified":"2018-04-18T13:17:07","modified_gmt":"2018-04-18T13:17:07","slug":"sql-plan-baselines-the-parallel-trap","status":"publish","type":"post","link":"https:\/\/www.spotonoracle.com\/?p=329","title":{"rendered":"SQL Plan Baselines &#8211; the parallel trap"},"content":{"rendered":"<p>Today, the good news is that I have time to write this blog post. The less good news is that our basement got flooded and I have to stay home. The bad news is, my current client does not allow remote work \ud83d\ude41<br \/>\nSo, blog post it is&#8230;<\/p>\n<p>There are a number of reasons why a SQL Plan Baseline might not get used. Here&#8217;s one I was not fully aware of until recently (although it makes perfect sense when you think about it): ALTER SESSION FORCE PARALLEL QUERY [PARALLEL n].<br \/>\nIn the simplest of cases the outcome whether a SQL Plan Baseline is used depends on the following:<\/p>\n<ul>\n<li>PARALLEL_DEGREE_POLICY parameter<\/li>\n<li>table decoration (DEGREE)<\/li>\n<li>optimizer enviroment used to generate the plan baseline (ENABLE PARALLEL \/ FORCE PARALLEL \/ FORCE PARALLEL n)<\/li>\n<li>optimizer environment of the session executing the query (ENABLE PARALLEL \/ FORCE PARALLEL \/ FORCE PARALLEL n)<\/li>\n<li>plan in the baseline (serial or parallel plan?)<\/li>\n<\/ul>\n<p>The base of the test case is a simple table that I&#8217;m going to select:<\/p>\n<pre class=\"brush: sql; collapse: false; title: ; wrap-lines: false; notranslate\" title=\"\">\r\ncreate table t1\r\nas\r\nselect rownum id, 'ABC' text\r\nfrom dual connect by level &lt;= 100\r\n;\r\n<\/pre>\n<p>For every combination of interest we run through the following procedure:<br \/>\n1) open and configure a new session for the parse environment on which the plan baseline is based<br \/>\n2) run this query &#8220;select * from t1&#8221;<br \/>\n3) create a fixed plan baseline for the generated plan<br \/>\n4) re-connect and configure the parse environment for the executing session<br \/>\n5) run query from step 2) and collect cursor information<br \/>\ndo steps 4) and 5) for ENABLE PARALLEL, FORCE PARALLEL, and FORCE PARALLEL n<\/p>\n<p><strong>Test 1:<\/strong> object DEGREE 1, parallel_degree_policy = manual<\/p>\n<table>\n<tr>\n<td><center>parsing session (SPB)<br \/>\/<br \/>executing session<\/center><\/td>\n<th>enable (serial plan)<\/th>\n<th>force (parallel plan)<\/th>\n<th>force 4 (parallel plan)<\/th>\n<\/tr>\n<tr>\n<th>enable (default)<\/th>\n<td>used<\/td>\n<td>not used (*3)<\/td>\n<td>not used (*3)<\/td>\n<\/tr>\n<tr>\n<th>force<\/th>\n<td>not used (*1)<\/td>\n<td>used<\/td>\n<td>used<\/td>\n<\/tr>\n<tr>\n<th>force 4<\/th>\n<td>not used (*2)<\/td>\n<td>used<\/td>\n<td>used<\/td>\n<\/tr>\n<\/table>\n<p>*1) Degree of Parallelism is 8 because of table property<br \/>\n*2) Degree of Parallelism is 4 because of session<br \/>\n*3) No note in the plan about DOP or baseline<br \/>\nSummary for test 1:<br \/>\nIf you have a serial plan in the baseline and use any force parallel on the session the plan baseline is not used and you get a parallel plan.<br \/>\nIf you have a parallel plan in the baseline and run the query on a session with ENABLE PARALLEL QUERY (default settings) the plan baseline is not used and you get a serial plan.<\/p>\n<p><strong>Test 2:<\/strong> object DEGREE 1, parallel_degree_policy = limited<\/p>\n<table>\n<tr>\n<td><center>parsing session (SPB)<br \/>\/<br \/>executing session<\/center><\/td>\n<th>enable (serial plan)<\/th>\n<th>force (parallel plan)<\/th>\n<th>force 4 (parallel plan)<\/th>\n<\/tr>\n<tr>\n<th>enable (default)<\/th>\n<td>used<\/td>\n<td>used<\/td>\n<td>used (*3)<\/td>\n<\/tr>\n<tr>\n<th>force<\/th>\n<td>not used (*1)<\/td>\n<td>used<\/td>\n<td>used (*3)<\/td>\n<\/tr>\n<tr>\n<th>force 4<\/th>\n<td>not used (*2)<\/td>\n<td>used<\/td>\n<td>used<\/td>\n<\/tr>\n<\/table>\n<p>*1) automatic DOP: Computed Degree of Parallelism is 2<br \/>\n*2) Degree of Parallelism is 4 because of session<br \/>\n*3) Degree of Parallelism is 2 because of hint<br \/>\nSummary for test 2:<br \/>\nIf you have a serial plan in the baseline and use any force parallel on the session the plan baseline is not used and you get a parallel plan.<br \/>\nNow that we allow for auto DOP the session with ENABLE PARALLEL QUERY can use parallel plans in plan baselines.<\/p>\n<p><strong>Test 3:<\/strong> object DEGREE DEFAULT, parallel_degree_policy = limited<\/p>\n<table>\n<tr>\n<td><center>parsing session (SPB)<br \/>\/<br \/>executing session<\/center><\/td>\n<th>enable (serial plan (*4))<\/th>\n<th>force (parallel plan)<\/th>\n<th>force 4 (parallel plan)<\/th>\n<\/tr>\n<tr>\n<th>enable (default)<\/th>\n<td>used<\/td>\n<td>used<\/td>\n<td>used (*3)<\/td>\n<\/tr>\n<tr>\n<th>force<\/th>\n<td>not used (*1)<\/td>\n<td>used<\/td>\n<td>used (*3)<\/td>\n<\/tr>\n<tr>\n<th>force 4<\/th>\n<td>not used (*2)<\/td>\n<td>used<\/td>\n<td>used<\/td>\n<\/tr>\n<\/table>\n<p>*1) automatic DOP: Computed Degree of Parallelism is 2<br \/>\n*2) Degree of Parallelism is 4 because of session<br \/>\n*3) Interestingly, there is no note about DOP in the plan at all. But it uses the plan baseline.<br \/>\n*4) automatic DOP: Computed Degree of Parallelism is 1 because of parallel threshold<br \/>\nSummary for test 3:<br \/>\nIf you have a serial plan in the baseline and use any force parallel on the session the plan baseline is not used and you get a parallel plan.<br \/>\nAgain, as we allow for auto DOP the session with ENABLE PARALLEL QUERY can use parallel plans in plan baselines. The result is the same as Test 2 but some the notes in the plans differ.<\/p>\n<p><strong>Test 4:<\/strong> object DEGREE DEFAULT, parallel_degree_policy = limited, fake stats so DOP > 1 for all plan baselines<\/p>\n<table>\n<tr>\n<td><center>parsing session (SPB)<br \/>\/<br \/>executing session<\/center><\/td>\n<th>enable (parallel plan (*1))<\/th>\n<th>force (parallel plan)<\/th>\n<th>force 4 (parallel plan)<\/th>\n<\/tr>\n<tr>\n<th>enable (default)<\/th>\n<td>used<\/td>\n<td>used<\/td>\n<td>used<\/td>\n<\/tr>\n<tr>\n<th>force<\/th>\n<td>used<\/td>\n<td>used<\/td>\n<td>used<\/td>\n<\/tr>\n<tr>\n<th>force 4<\/th>\n<td>used<\/td>\n<td>used<\/td>\n<td>used<\/td>\n<\/tr>\n<\/table>\n<p>*1) automatic DOP: Computed Degree of Parallelism is 2<br \/>\nSummary for test 4:<br \/>\nNaturally, now that we always have parallel plans in the plan baselines and the object statistics call for auto DOP > 1 the plan baselines get used in all cases.<\/p>\n<p>Why did I do this? See, there&#8217;s this batch job with a SQL that has a SQL Plan Baseline on it (serial plan). Now, every once in a while the run-time of this batch job goes through the roof and every time this happens I see that the query does not use the baseline (v$sql.sql_plan_baseline is NULL). Also, next to different PLAN_HASH_VALUEs I noticed different OPTIMIZER_ENV_HASH_VALUEs. Checking the session settings V$SES_OPTIMIZER_ENV showed that &#8220;parallel_query_forced_dop&#8221; was set to &#8220;default&#8221;, which means &#8220;ALTER SESSION FORCE PARALLEL QUERY&#8221; was run previously on that session.<br \/>\nBut why is it not deterministic? The tool that runs all the batch jobs uses a connection pool, some job steps force parallel and some don&#8217;t. We haven&#8217;t been able to technically confirm this but everything points towards that this session property is not cleared to default when a connection gets reused. So, sometimes this batch job just gets unlucky by the session it gets from the connection pool.<br \/>\nThe solution: Adding second SQL Plan Baseline. This plan is a parallel plan with the same structure as the original serial plan. Now, either one of the plan baselines (serial or parallel plan) is being used depending on the session configuration.<\/p>\n<p>Footnote:<br \/>\nWhen you use &#8220;FORCE PARALLEL QUERY&#8221; you might get a serial plan. You&#8217;ll see this in the plan notes: &#8220;automatic DOP: Computed Degree of Parallelism is 1&#8221;. Obviously, this would change some of above results.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today, the good news is that I have time to write this blog post. The less good news is that our basement got flooded and I have to stay home. The bad news is, my current client does not allow remote work \ud83d\ude41 So, blog post it is&#8230; There are a number of reasons why [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,13],"tags":[],"class_list":["post-329","post","type-post","status-publish","format-standard","hentry","category-internals","category-things-that-happen"],"_links":{"self":[{"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=\/wp\/v2\/posts\/329","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=329"}],"version-history":[{"count":8,"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=\/wp\/v2\/posts\/329\/revisions"}],"predecessor-version":[{"id":344,"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=\/wp\/v2\/posts\/329\/revisions\/344"}],"wp:attachment":[{"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=329"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=329"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.spotonoracle.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=329"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}