{"id":2878,"date":"2019-08-25T17:13:19","date_gmt":"2019-08-25T17:13:19","guid":{"rendered":"https:\/\/nenadnoveljic.com\/blog\/?p=2878"},"modified":"2019-09-02T08:50:57","modified_gmt":"2019-09-02T08:50:57","slug":"ojppd","status":"publish","type":"post","link":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/","title":{"rendered":"Old-style (non-cost-based) Join Predicate Push-Down Transformation"},"content":{"rendered":"<p>Generally, join predicate push-down (JPPD) transformation is cost based. However, sometimes the optimizer falls back to the old-style (non-cost-based) JPPD (OJPPD). In such a case cost can be massively underestimated and the effect on the performance detrimental.<\/p>\n<p>I&#8217;ll be using a simple data set for demonstrating this on a 18.7 Oracle database:<\/p>\n<pre><code>create table t1 (n1 integer) ;\ncreate table t2 (n1 integer, constraint pk_t2 primary key (n1)) ;\ncreate table t3 (n1 integer, n2 integer) ;\ncreate table t4 (n1 integer, c1 varchar2(4000)) ;\n\ninsert into t4 select 1, lpad('A',4000,'A') \n  from dual connect by level &lt;=100000 ;\ncommit ;\n\nbegin\n  dbms_stats.gather_table_stats(null, 'T1' );\n  dbms_stats.gather_table_stats(null, 'T2' );\n  dbms_stats.gather_table_stats(null, 'T3' );\n  dbms_stats.gather_table_stats(null, 'T4' );\nend;\n\/\n\nset pagesize 0\nset linesize 200<\/code><\/pre>\n<p>Let&#8217;s start with a straightfoward query that produces a plan with JPPD:<\/p>\n<pre><code>select \/*+ qb_name(MAIN) *\/ t1.n1 from \n  t1,\n  ( \n    select \/*+ qb_name(RECEIVER) *\/ t2.n1 from t2, t4\n      where t4.n1 = t2.n1\n  ) v1\n where t1.n1 = v1.n1(+) \n;\n\nselect * from table(dbms_xplan.display_cursor(NULL,NULL)) ;\n\n---------------------------------------------------------------------------------\n| Id  | Operation               | Name  | Rows  | Bytes | Cost (%CPU)| Time     |\n---------------------------------------------------------------------------------\n|   0 | SELECT STATEMENT        |       |       |       |  <span style=\"color: blue;\">1615<\/span> (100)|          |\n|   1 |  NESTED LOOPS OUTER     |       |     1 |    15 |  <span style=\"color: blue;\">1615<\/span>   (1)| 00:00:01 |\n|   2 |   TABLE ACCESS FULL     | T1    |     1 |    13 |     2   (0)| 00:00:01 |\n|   3 |   VIEW PUSHED PREDICATE |       |     1 |     2 |  <span style=\"color: blue;\">1613<\/span>   (1)| 00:00:01 |\n|   4 |    NESTED LOOPS         |       |   100K|  1562K|  <span style=\"color: blue;\">1613<\/span>   (1)| 00:00:01 |\n|*  5 |     INDEX UNIQUE SCAN   | PK_T2 |     1 |    13 |     0   (0)|          |\n|*  6 |     TABLE ACCESS FULL   | T4    |   100K|   292K|  1613   (1)| 00:00:01 |\n---------------------------------------------------------------------------------\n\nPredicate Information (identified by operation id):\n---------------------------------------------------\n\n   5 - access(\"T2\".\"N1\"=\"T1\".\"N1\")\n   6 - filter(\"T4\".\"N1\"=\"T1\".\"N1\")<\/code><\/pre>\n<p>It&#8217;s worth noting that the nested loop (NL) in the query block (QB) RECEIVER is the main contributor to the total cost. That&#8217;s the QB which receives the pushed predicate.<\/p>\n<p>The optimizer trace confirms the JPPD transformation:<\/p>\n<pre><code>JPPD:  Considering Cost-based predicate pushdown from query block MAIN (#1)\nCost-based predicate pushdown (JPPD)\nJPPD: Checking validity of push-down in query block MAIN (#1)\nJPPD:   Checking validity of push-down from query block MAIN (#1) to query block RECEIVER (#2)\nJPPD:     Passed validity checks\nJPPD: JPPD:   Pushdown from query block MAIN (#1) passed validity checks.\nJPPD: Using search type: linear\nJPPD: Considering join predicate push-down\nJPPD: Starting iteration 1, state space = (2) : (0)\nJPPD: Performing join predicate push-down (no transformation phase) from query block MAIN (#1) to query block RECEIVER (#2)\nJPPD: Costing transformed query.\nJPPD: Updated best state, Cost = 1615.054794\nJPPD: Starting iteration 2, state space = (2) : (1)\nJPPD: Performing join predicate push-down (candidate phase) from query block MAIN (#1) to query block RECEIVER (#2)\nJPPD:   Pushing predicate \"T1\".\"N1\"=\"V1\".\"N1\"(+)\nJPPD: Push dest of pred 0x80c9c730 is qb 0x80cab7b0:query block RECEIVER (#2)\nJPPD: Costing transformed query.\nJPPD: Retrieved original view card: 1.000000\nJPPD: Updated best state, Cost = 1614.996808\nJPPD: Will use JPPD from MAIN (#1) to RECEIVER (#2).\nJPPD: Applying transformation directives\nJPPD: Checking validity of push-down in query block MAIN (#1)\nJPPD: JPPD:   Pushdown from query block MAIN (#1) passed validity checks.\nJPPD: Performing join predicate push-down (final phase) from query block MAIN (#1) to query block RECEIVER (#2)\nJPPD:   Pushing predicate \"T1\".\"N1\"=\"V1\".\"N1\"(+)\nJPPD: Push dest of pred 0x80cab828 is qb 0x80cfeda0:query block RECEIVER (#2)\nJPPD: Retrieved original view card: 1.000000<\/code><\/pre>\n<p>But the cost suddenly drops after adding a hierarchical subquery:<\/p>\n<pre><code>select \/*+ qb_name(MAIN) *\/ t1.n1 from \n  t1,\n  ( \n    select \/*+ qb_name(RECEIVER) *\/ t2.n1 from t2, t4\n      where t4.n1 = t2.n1\n  ) v1,\n  (\n    select \/*+ qb_name(hierarchical) *\/ t3.n1 n1 from t3 \n\t  <span style=\"color: red;\">connect by n2 = prior n1<\/span>\n  ) v2\n where t1.n1 = v1.n1(+) and t1.n1 = v2.n1 \n;\n\nselect * from table(dbms_xplan.display_cursor(NULL,NULL)) ;\n\n----------------------------------------------------------------------------------------\n| Id  | Operation                      | Name  | Rows  | Bytes | Cost (%CPU)| Time     |\n----------------------------------------------------------------------------------------\n|   0 | SELECT STATEMENT               |       |       |       |     <span style=\"color: red;\">4<\/span> (100)|          |\n|*  1 |  HASH JOIN                     |       |     1 |    39 |     <span style=\"color: red;\">4<\/span>   (0)| 00:00:01 |\n|   2 |   NESTED LOOPS OUTER           |       |     1 |    26 |     <span style=\"color: red;\">2<\/span>   (0)| 00:00:01 |\n|   3 |    TABLE ACCESS FULL           | T1    |     1 |    13 |     2   (0)| 00:00:01 |\n|   4 |    VIEW PUSHED PREDICATE       |       |     1 |    13 |     <span style=\"color: red;\">0<\/span>   (0)|          |\n|   5 |     NESTED LOOPS               |       |     1 |    16 |  <span style=\"color: blue;\">1613<\/span>   (1)| 00:00:01 |\n|*  6 |      INDEX UNIQUE SCAN         | PK_T2 |     1 |    13 |     0   (0)|          |\n|*  7 |      TABLE ACCESS FULL         | T4    |     1 |     3 |  1613   (1)| 00:00:01 |\n|   8 |   VIEW                         |       |     1 |    13 |     2   (0)| 00:00:01 |\n|*  9 |    CONNECT BY WITHOUT FILTERING|       |       |       |            |          |\n|  10 |     TABLE ACCESS FULL          | T3    |     1 |    26 |     2   (0)| 00:00:01 |\n----------------------------------------------------------------------------------------\n\nPredicate Information (identified by operation id):\n---------------------------------------------------\n\n   1 - access(\"T1\".\"N1\"=\"V2\".\"N1\")\n   6 - access(\"T2\".\"N1\"=\"T1\".\"N1\")\n   7 - filter((\"T4\".\"N1\"=\"T2\".\"N1\" AND \"T4\".\"N1\"=\"T1\".\"N1\"))\n   9 - access(\"N2\"=PRIOR NULL)<\/code><\/pre>\n<p>So instead of slightly increasing, the cost slumped. As you can see, the NL cost in the step 5 wasn&#8217;t propagated to its parent. The magnitude of the error is proportional to the following two values: QB RECEIVER cost and outer row source size. That&#8217;s not surprising at all, because the total cost is calculated as QB_RECEIVER_cost * num_outer_rows.<\/p>\n<p>The 10053 trace tells us that the optimizer, surprisingly, switched from JPPD to OJPPD:<\/p>\n<pre><code>JPPD - join predicate push-down\nOJPPD - old-style (non-cost-based) JPPD\nOJPPD: Promoting index PK_T2\nOJPPD: Performing join predicate push-down  to query block RECEIVER (#0)\nOJPPD: Pushing predicate \"T1\".\"N1\"=\"V1\".\"N1\"(+)\nOJPPD: Used promoted index: PK_T2\nOJPPD: Performing join predicate push-down  to query block RECEIVER (#0)\nOJPPD: Pushing predicate \"T1\".\"N1\"=\"V1\".\"N1\"(+)\nOJPPD: Used promoted index: PK_T2<\/code><\/pre>\n<p>Finally, I&#8217;m going to show an extremely unlucky case &#8211; with a large outer row source. To do that, first I&#8217;m going to insert lots of rows into the outer table T1.<\/p>\n<pre><code>insert into t1 select 1\n  from dual connect by level &lt;=1e6 ;\ncommit ;\n\nexec dbms_stats.gather_table_stats(null, 'T1' );<\/code><\/pre>\n<p>Expectedly, the execution plan for the query without the hierarchical subquery changed &#8211; JPPD isn&#8217;t performed anymore because the transformed query cost exploded after increasing the outer row source size.<\/p>\n<pre><code>select \/*+ qb_name(MAIN) *\/ t1.n1 from \n  t1,\n  ( \n    select \/*+ qb_name(RECEIVER) *\/ t2.n1 from t2, t4\n      where t4.n1 = t2.n1\n  ) v1\n where t1.n1 = v1.n1(+) \n;\n\nselect * from table(dbms_xplan.display_cursor(NULL,NULL)) ;\n\n-------------------------------------------------------------------------------\n| Id  | Operation             | Name  | Rows  | Bytes | Cost (%CPU)| Time     |\n-------------------------------------------------------------------------------\n|   0 | SELECT STATEMENT      |       |       |       |  1659 (100)|          |\n|*  1 |  HASH JOIN RIGHT OUTER|       |  1000K|    15M|  1659   (1)| 00:00:01 |\n|   2 |   VIEW                |       |     1 |    13 |  1613   (1)| 00:00:01 |\n|*  3 |    HASH JOIN          |       |     1 |    16 |  1613   (1)| 00:00:01 |\n|   4 |     INDEX FULL SCAN   | PK_T2 |     1 |    13 |     0   (0)|          |\n|   5 |     TABLE ACCESS FULL | T4    |   100K|   292K|  1613   (1)| 00:00:01 |\n|   6 |   TABLE ACCESS FULL   | T1    |  1000K|  2929K|    45   (3)| 00:00:01 |\n-------------------------------------------------------------------------------\n\nPredicate Information (identified by operation id):\n---------------------------------------------------\n\n   1 - access(\"T1\".\"N1\"=\"V1\".\"N1\")\n   3 - access(\"T4\".\"N1\"=\"T2\".\"N1\")<\/code><\/pre>\n<p>The optimizer trace shows the exact costs of both transformed and non-transformed queries:<\/p>\n<pre><code><a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a> -v qb=MAIN DB_ora_13845.trc\n---------------\n36 Registered qb: MAIN 0x86311848 (HINT MAIN)\n1181 JPPD: Performing join predicate push-down (<span style=\"color: blue;\">no transformation<\/span> phase) from query block MAIN (#1) to query block RECEIVER (#2)\n1689 Final cost for query block MAIN (#1) - All Rows Plan:\n1690   Best join order: 1\n1691   Cost: <span style=\"color: blue;\">1659.234715<\/span>  Degree: 1  Card: 1000000.000000  Bytes: 16000000.000000\n---------------\n36 Registered qb: MAIN 0x86311848 (HINT MAIN)\n1704 JPPD: Performing join predicate push-down (<span style=\"color: red;\">candidate<\/span> phase) from query block MAIN (#1) to query block RECEIVER (#2)\n2065 Final cost for query block MAIN (#1) - All Rows Plan:\n2066   Best join order: 1\n2067   Cost: <span style=\"color: red;\">1612996725.467509<\/span>  Degree: 1  Card: 1000000.000000  Bytes: 5000000.000000\n---------------\n36 Registered qb: MAIN 0x86311848 (HINT MAIN)\n2089 JPPD: Performing join predicate push-down (no transformation phase) from query block MAIN (#1) to query block RECEIVER (#2)\n2741 Final cost for query block MAIN (#1) - All Rows Plan:\n2742   Best join order: 1\n2743   Cost: 1659.234715  Degree: 1  Card: 1000000.000000  Bytes: 16000000.000000<\/code><\/pre>\n<p>By the way, <a href=\"https:\/\/github.com\/nenadnoveljic\/blogs\/blob\/master\/extracting_query_block_optimizer_trace\/opt_qb.awk\">opt_qb.awk<\/a> comes in handy for analyzing query transformations. It&#8217;s an awk script for extracting the  essential information about QBs and is documented in a <a href=\"https:\/\/nenadnoveljic.com\/blog\/extracting-query-block-optimizer-trace\/\">previous blog post<\/a>.<\/p>\n<p>In contrast, the execution plan for the query with the hierarchical subquery still contains the PUSHED PREDICATE operation:<\/p>\n<pre><code>-----------------------------------------------------------------------------------------\n| Id  | Operation                       | Name  | Rows  | Bytes | Cost (%CPU)| Time     |\n-----------------------------------------------------------------------------------------\n|   0 | SELECT STATEMENT                |       |       |       |    48 (100)|          |\n|   1 |  NESTED LOOPS OUTER             |       |     1 |    29 |    48   (5)| 00:00:01 |\n|*  2 |   HASH JOIN                     |       |     1 |    16 |    48   (5)| 00:00:01 |\n|   3 |    VIEW                         |       |     1 |    13 |     2   (0)| 00:00:01 |\n|*  4 |     CONNECT BY WITHOUT FILTERING|       |       |       |            |          |\n|   5 |      TABLE ACCESS FULL          | T3    |     1 |    26 |     2   (0)| 00:00:01 |\n|   6 |    TABLE ACCESS FULL            | T1    |  1000K|  2929K|    45   (3)| 00:00:01 |\n|   7 |   VIEW PUSHED PREDICATE         |       |     1 |    13 |     <span style=\"color: red;\">0<\/span>   (0)|          |\n|   8 |    NESTED LOOPS                 |       |     1 |    16 |  1613   (1)| 00:00:01 |\n|*  9 |     INDEX UNIQUE SCAN           | PK_T2 |     1 |    13 |     0   (0)|          |\n|* 10 |     TABLE ACCESS FULL           | T4    |     1 |     3 |  1613   (1)| 00:00:01 |\n-----------------------------------------------------------------------------------------\n\nPredicate Information (identified by operation id):\n---------------------------------------------------\n\n   2 - access(\"T1\".\"N1\"=\"V2\".\"N1\")\n   4 - access(\"N2\"=PRIOR NULL)\n   9 - access(\"T2\".\"N1\"=\"T1\".\"N1\")\n  10 - filter((\"T4\".\"N1\"=\"T2\".\"N1\" AND \"T4\".\"N1\"=\"T1\".\"N1\"))<\/code><\/pre>\n<p>In this particular case, the cost was hugely underestimated &#8211; by the factor 33 million.<\/p>\n<p>A possible workaround is to selectively disable pushing predicates with the following hint:<\/p>\n<pre><code>opt_param('_push_join_predicate', 'false')<\/code><\/pre>\n<p>On the downside, this will also prevent useful predicates from being pushed.<\/p>\n<p>In summary, hierarchical subqueries can lead to suboptimal execution plans in conjunction with JPPD. The cost will be massively underestimated for large outer row sources. This problem can be easily detected by comparing the VIEW PUSHED PREDICATE cost to its children &#8211; VIEW PUSHED PREDICATE has a lower cost. In fact, I&#8217;m just thinking of writing a procedure for parsing execution plans and reporting such issues.<\/p>\n<h1>Update on August 25th 2019<\/h1>\n<p>The wrong cost calculation seems to be caused by the bug 22582700. The issue is fixed in Oracle 19.3.<br \/>\nMany thanks to Timur Akhmadeev for providing this information (see the comments section).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Suboptimal execution plans after falling back to OJPPD with hierarchical subqueries  <a href=\"https:\/\/nenadnoveljic.com\/blog\/ojppd\/\" class=\"more-link\">Continue Reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[11,28,5],"tags":[],"class_list":["post-2878","post","type-post","status-publish","format-standard","hentry","category-cost-based-optimizer","category-join-predicate-push-down-jppd","category-oracle"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Old-style (non-cost-based) Join Predicate Push-Down Transformation - All-round Database Topics<\/title>\n<meta name=\"description\" content=\"Suboptimal execution plans after falling back to OJPPD with hierarchical subqueries\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/nenadnoveljic.com\/blog\/ojppd\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Old-style (non-cost-based) Join Predicate Push-Down Transformation - All-round Database Topics\" \/>\n<meta property=\"og:description\" content=\"Suboptimal execution plans after falling back to OJPPD with hierarchical subqueries\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nenadnoveljic.com\/blog\/ojppd\/\" \/>\n<meta property=\"og:site_name\" content=\"All-round Database Topics\" \/>\n<meta property=\"article:published_time\" content=\"2019-08-25T17:13:19+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-09-02T08:50:57+00:00\" \/>\n<meta name=\"author\" content=\"Nenad Noveljic\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@NenadNoveljic\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Nenad Noveljic\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/\"},\"author\":{\"name\":\"Nenad Noveljic\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"headline\":\"Old-style (non-cost-based) Join Predicate Push-Down Transformation\",\"datePublished\":\"2019-08-25T17:13:19+00:00\",\"dateModified\":\"2019-09-02T08:50:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/\"},\"wordCount\":465,\"commentCount\":1,\"articleSection\":[\"cost based optimizer\",\"join predicate push-down (JPPD)\",\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/\",\"name\":\"Old-style (non-cost-based) Join Predicate Push-Down Transformation - All-round Database Topics\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#website\"},\"datePublished\":\"2019-08-25T17:13:19+00:00\",\"dateModified\":\"2019-09-02T08:50:57+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"description\":\"Suboptimal execution plans after falling back to OJPPD with hierarchical subqueries\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/ojppd\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Old-style (non-cost-based) Join Predicate Push-Down Transformation\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/\",\"name\":\"All-round Database Topics\",\"description\":\"Nenad Noveljic\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\",\"name\":\"Nenad Noveljic\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g\",\"caption\":\"Nenad Noveljic\"},\"sameAs\":[\"nenad-noveljic-9b746a6\",\"https:\\\/\\\/x.com\\\/NenadNoveljic\"],\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/author\\\/nenad\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Old-style (non-cost-based) Join Predicate Push-Down Transformation - All-round Database Topics","description":"Suboptimal execution plans after falling back to OJPPD with hierarchical subqueries","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/","og_locale":"en_US","og_type":"article","og_title":"Old-style (non-cost-based) Join Predicate Push-Down Transformation - All-round Database Topics","og_description":"Suboptimal execution plans after falling back to OJPPD with hierarchical subqueries","og_url":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/","og_site_name":"All-round Database Topics","article_published_time":"2019-08-25T17:13:19+00:00","article_modified_time":"2019-09-02T08:50:57+00:00","author":"Nenad Noveljic","twitter_card":"summary_large_image","twitter_creator":"@NenadNoveljic","twitter_misc":{"Written by":"Nenad Noveljic","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/#article","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/"},"author":{"name":"Nenad Noveljic","@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"headline":"Old-style (non-cost-based) Join Predicate Push-Down Transformation","datePublished":"2019-08-25T17:13:19+00:00","dateModified":"2019-09-02T08:50:57+00:00","mainEntityOfPage":{"@id":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/"},"wordCount":465,"commentCount":1,"articleSection":["cost based optimizer","join predicate push-down (JPPD)","Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/nenadnoveljic.com\/blog\/ojppd\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/","url":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/","name":"Old-style (non-cost-based) Join Predicate Push-Down Transformation - All-round Database Topics","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#website"},"datePublished":"2019-08-25T17:13:19+00:00","dateModified":"2019-09-02T08:50:57+00:00","author":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"description":"Suboptimal execution plans after falling back to OJPPD with hierarchical subqueries","breadcrumb":{"@id":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nenadnoveljic.com\/blog\/ojppd\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/nenadnoveljic.com\/blog\/ojppd\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nenadnoveljic.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Old-style (non-cost-based) Join Predicate Push-Down Transformation"}]},{"@type":"WebSite","@id":"https:\/\/nenadnoveljic.com\/blog\/#website","url":"https:\/\/nenadnoveljic.com\/blog\/","name":"All-round Database Topics","description":"Nenad Noveljic","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/nenadnoveljic.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa","name":"Nenad Noveljic","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a97b796613ea48ec8a7b79c8ffe1c685dcffc920c68121f6238d5caab5070670?s=96&d=mm&r=g","caption":"Nenad Noveljic"},"sameAs":["nenad-noveljic-9b746a6","https:\/\/x.com\/NenadNoveljic"],"url":"https:\/\/nenadnoveljic.com\/blog\/author\/nenad\/"}]}},"_links":{"self":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2878","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/comments?post=2878"}],"version-history":[{"count":1,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2878\/revisions"}],"predecessor-version":[{"id":2908,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2878\/revisions\/2908"}],"wp:attachment":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/media?parent=2878"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/categories?post=2878"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/tags?post=2878"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}