{"id":2278,"date":"2018-12-05T21:29:17","date_gmt":"2018-12-05T21:29:17","guid":{"rendered":"https:\/\/nenadnoveljic.com\/blog\/?p=2278"},"modified":"2020-10-02T16:43:48","modified_gmt":"2020-10-02T16:43:48","slug":"dissecting-cost-based-or-expansion","status":"publish","type":"post","link":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/","title":{"rendered":"Dissecting Cost Based OR-Expansion"},"content":{"rendered":"<h1>Cost Based OR-Expansion<\/h1>\n<p>In a nutshell, the OR-expansion (ORE) is the transformation where an OR operator is transformed to a UNION ALL set operation, like:<\/p>\n<pre><code>select  \/*+ OPT_PARAM('_B_TREE_BITMAP_PLANS','FALSE') *\/ \n  * from t where n1 = 1 <span style=\"color:brown\">or<\/span> n2 = 1 ;\n\n-------------------------------------------------------------------------------------------------\n| Id  | Operation                     | Name            | Rows  | Bytes | Cost (%CPU)| Time     |\n-------------------------------------------------------------------------------------------------\n|   0 | SELECT STATEMENT              |                 |       |       |     5 (100)|          |\n|   1 |  VIEW                         | VW_<span style=\"color:brown\">ORE<\/span>_1B35BA0F |     3 |   117 |     5   (0)| 00:00:01 |\n|   2 |   <span style=\"color:brown\">UNION-ALL<\/span>                   |                 |       |       |            |          |\n|   3 |    TABLE ACCESS BY INDEX ROWID| T               |     1 |    12 |     2   (0)| 00:00:01 |\n|*  4 |     INDEX RANGE SCAN          | T_IDX1          |     1 |       |     1   (0)| 00:00:01 |\n|*  5 |    TABLE ACCESS BY INDEX ROWID| T               |     2 |    24 |     3   (0)| 00:00:01 |\n|*  6 |     INDEX RANGE SCAN          | T_IDX2          |     2 |       |     1   (0)| 00:00:01 |\n-------------------------------------------------------------------------------------------------\n\nPredicate Information (identified by operation id):\n---------------------------------------------------\n\n   4 - access(\"N1\"=1)\n   5 - filter(LNNVL(\"N1\"=1))\n   6 - access(\"N2\"=1)<\/code><\/pre>\n<p>It wasn&#8217;t until release 12.2 that this transformation became cost based.<\/p>\n<p>In this blog post I&#8217;ll be explaining how to understand the cost based OR-Expansion (CBORE) optimizer calculations and decisions by analyzing the information in the 10053 trace.<\/p>\n<p>I&#8217;ll be using the following table for demonstration purposes:<\/p>\n<pre><code>create table t  \nas\n  select level n1, mod(level,5000) n2, level n3\n    from dual connect by level &lt;=10000 ;\n\ncreate index t_idx1 on t(n1);\ncreate index t_idx2 on t(n2);\ncreate index t_idx3 on t(n3);<\/code><\/pre>\n<p>Let&#8217;s start with generating the execution plan for the following simple query with a single OR operation:<\/p>\n<pre><code>select  \/*+ OPT_PARAM('_B_TREE_BITMAP_PLANS','FALSE') *\/ \n  * from t where <span style=\"color:red\">n1 = 1<\/span> or <span style=\"color:blue\">n2 = 1<\/span> <\/code><\/pre>\n<h1>CBO (10053) trace analysis<\/h1>\n<p>We can see that the optimizer decided to consider CBORE:<\/p>\n<pre><code>ORE: Predicate chain after QB validity check - SEL$1\n<span style=\"color:red\">\"T\".\"N1\"=1<\/span> OR <span style=\"color:blue\">\"T\".\"N2\"=1<\/span>\nRegistered qb: SEL$1 0x8384b0c0 (COPY SEL$1)<\/code><\/pre>\n<p>Further, the optimizer built a conjunction chain for each operand:<\/p>\n<pre><code>DNF Matrix (Before sorting OR branches)\n             P1  P2\nCNJ (#1) :   <span style=\"color:red\">1<\/span>   0\n\nCNJ (#2) :   0   <span style=\"color:blue\">1<\/span>\n\nORE:  Predicate list\n<span style=\"color:red\">P1 : \"T\".\"N1\"=1<\/span>\n<span style=\"color:blue\">P2 : \"T\".\"N2\"=1<\/span><\/code><\/pre>\n<p>The conjunction chain matrix above is just another representation of our WHERE clause <span style=\"color:red\">&#8220;T&#8221;.&#8221;N1&#8243;=1<\/span> OR <span style=\"color:blue\">&#8220;T&#8221;.&#8221;N2&#8243;=1<\/span>. Simply put, each conjunction chain (CNJ) &#8211; represented as a row in the matrix above &#8211; is an OR operand. The value of the matrix element &#8220;1&#8221; in the first CNJ means that the query block contains the OR operand <span style=\"color:red\">P1<\/span>, that is <span style=\"color:red\">&#8220;T&#8221;.&#8221;N1&#8243;=1<\/span>. For a WHERE clause consisting of solely OR operators, each conjunction chain contains a single &#8220;1&#8221; value and the rest are zeros. At the first sight, it might look counterintuitive to represent an inherently disjunctive OR using a conjunctive chain, but I&#8217;m going to explain later why it makes sense to do so.<\/p>\n<p>Anyway, for our simple single OR operator there are only two possibilities to choose from. We can either forgo CBORE and leave the query as it is or transform it to a UNION ALL query with two query blocks &#8211; one for each OR operand. The optimizer informed us about that:<\/p>\n<pre><code>ORE: Switching to two pass because of # conjunction: 2<\/code><\/pre>\n<p>In the first iteration, the optimizer calculated the cost for the query block containing both OR operands.<\/p>\n<pre><code>ORE: Starting iteration 1, state space = [{ <span style=\"color:red\">1<\/span> <span style=\"color:blue\">2<\/span> }]\nORE: Transformed query\n******* UNPARSED QUERY IS *******\nSELECT \"T\".\"N1\" \"N1\",\"T\".\"N2\" \"N2\",\"T\".\"N3\" \"N3\" FROM \"VAR\".\"T\" \"T\" WHERE \"T\".\"N1\"=1 OR \"T\".\"N2\"=1\nFPD: Considering simple filter push in query block SEL$1 (#1)\n<span style=\"color:red\">\"T\".\"N1\"=1<\/span> OR <span style=\"color:blue\">\"T\".\"N2\"=1<\/span>\nry to generate transitive predicate from check constraints for query block SEL$1 (#1)\nfinally: <span style=\"color:red\">\"T\".\"N1\"=1<\/span> OR <span style=\"color:blue\">\"T\".\"N2\"=1<\/span>\n\nORE: Costing transformed query.\nCBQT: Looking for cost annotations for query block SEL$1, key = SEL$1_00000000_0\nCBQT: Could not find stored cost annotations.<\/code><\/pre>\n<p>The state space numbers in the excerpt above are telling us which OR operands are contained in the query block that is currently being costed. As the state space in the first iteration is [{ <span style=\"color:red\">1<\/span> <span style=\"color:blue\">2<\/span> }], the query block contains both OR operands: <span style=\"color:red\">P1<\/span> and <span style=\"color:blue\">P2<\/span>. In other words, the optimizer calculated the cost for the non-transformed query:<\/p>\n<pre><code>Best:: AccessPath: TableScan\nCost: 9.120737  Degree: 1  Resp: 9.120737  Card: 2.999800  Bytes: 0.000000\n\nBest so far:  Table#: 0  cost: 9.120737  card: 2.999800  bytes: 36.000000\n\t\nFinal cost for query block SEL$1 (#1) - All Rows Plan:\nBest join order: 1\nCost: 9.120737  Degree: 1  Card: 3.000000  Bytes: 36.000000<\/code><\/pre>\n<p>The optimizer stored the calculated cost before moving to the next iteration:<\/p>\n<pre><code>ORE: Updated best state, Cost = 9.120737<\/code><\/pre>\n<p>In the next iteration, the optimizer calculated the cost for two query blocks, each of them containing only one OR operand:<\/p>\n<pre><code>ORE: Starting iteration 2, state space = [{ <span style=\"color:red\">1<\/span> }]\nORE: Transformed query\n******* UNPARSED QUERY IS *******\nSELECT \"T\".\"N3\" \"ITEM_1\",\"T\".\"N2\" \"ITEM_2\",\"T\".\"N1\" \"ITEM_3\" FROM \"VAR\".\"T\" \"T\" WHERE \"T\".\"N1\"=1\nFPD: Considering simple filter push in query block SEL$1 (#1)llllll\n<span style=\"color:red\">\"T\".\"N1\"=1<\/span>\ntry to generate transitive predicate from check constraints for query block SEL$1 (#1)\nfinally: <span style=\"color:red\">\"T\".\"N1\"=1<\/span>\n...\nBest:: AccessPath: IndexRange\nIndex: T_IDX1\nCost: 2.000645  Degree: 1  Resp: 2.000645  Card: 1.000000  Bytes: 0.000000\n...\nBest so far:  Table#: 0  cost: 2.000645  card: 1.000000  bytes: 12.000000\n...\nCost: 2.000645  Degree: 1  Card: 1.000000  Bytes: 12.000000\n...   \n   \nORE: Starting iteration 2, state space = [{ <span style=\"color:blue\">2<\/span> }]\nORE: Transformed query\n******* UNPARSED QUERY IS *******\nSELECT \"T\".\"N3\" \"ITEM_1\",\"T\".\"N2\" \"ITEM_2\",\"T\".\"N1\" \"ITEM_3\" FROM \"VAR\".\"T\" \"T\" WHERE \"T\".\"N2\"=1 AND LNNVL(\"T\".\"N1\"=1)\nFPD: Considering simple filter push in query block SEL$1 (#1)\n<span style=\"color:blue\">\"T\".\"N2\"=1 AND LNNVL(\"T\".\"N1\"=1)<\/span>\ntry to generate transitive predicate from check constraints for query block SEL$1 (#1)\nfinally: <span style=\"color:blue\">\"T\".\"N2\"=1 AND LNNVL(\"T\".\"N1\"=1)<\/span>\n...   \nORE: Costing transformed query.\n...   \nBest so far:  Table#: 0  cost: 3.000962  card: 1.999800  bytes: 24.000000\n...\nFinal cost for query block SEL$1 (#1) - All Rows Plan:\nBest join order: 1\nCost: 3.000962  Degree: 1  Card: 2.000000  Bytes: 24.000000<\/code><\/pre>\n<p>The cost of the transformed UNION ALL query is calculated as the sum of the both query blocks costs. Since this cost is lower than the cost of the original query, the optimizer went with CBORE in this particular case.<\/p>\n<pre><code>kkoqbc: finish optimizing query block SEL$1 (#1)\nORE: Updated best state, Cost = 5.001606\nORE:   Transferring best state space to preserved query.\nORE:   Transferring best state space to original query.<\/code><\/pre>\n<h1>Multiple OR operators<\/h1>\n<p>Using the information above, it&#8217;s easy to extract the essential information for understanding the CBORE decision making:<\/p>\n<pre><code>egrep \"state space|Updated best state|Not update best state\" DB1_ora_17091_CBORE.trc<\/code><\/pre>\n<p>Here&#8217;s is the decision tree for our example:<\/p>\n<pre><code>ORE: Starting iteration 1, state space = [{ <span style=\"color:red\">1<\/span> <span style=\"color:blue\">2<\/span> }]\nORE: Updated best state, Cost = 9.120737\nORE: Starting iteration 2, state space = [{ <span style=\"color:red\">1<\/span> }]\nORE: Updated best state, Cost = 2.000645\nORE: Starting iteration 2, state space = [{ <span style=\"color:blue\">2<\/span> }]\nORE: Updated best state, Cost = 5.001606\nORE:   Transferring best state space to preserved query. \nORE:   Transferring best state space to original query.<\/code><\/pre>\n<p>Let&#8217;s extend our query with an additional OR operator:<\/p>\n<pre><code>select  \/*+ OPT_PARAM('_B_TREE_BITMAP_PLANS','FALSE') *\/ \n  * from t where n1 = 1 or n3 = 1 or n2 = 1 ;\n\nORE: Starting iteration 1, state space = [{ 1 2 3 }]\nORE: Updated best state, Cost = 9.149879\nORE: Starting iteration 2, state space = [{ 1 }]\nORE: Updated best state, Cost = 2.000645\nORE: Starting iteration 2, state space = [{ 2 }]\nORE: Updated best state, Cost = 5.001606\nORE: Starting iteration 2, state space = [{ 3 }]\nORE: Updated best state, Cost = 7.002255\nORE: Starting iteration 3, state space = [{ 1 }]\nORE: Updated best state, Cost = 2.000645\nORE: Starting iteration 3, state space = [{ 2 3 }]\nORE: Not update best state, Cost = 11.129714\nORE: Starting iteration 4, state space = [{ 1 2 }]\nORE: Not update best state, Cost = 9.120737\nORE:   Transferring best state space to preserved query. \nORE:   Transferring best state space to original query.<\/code><\/pre>\n<p>We can draw the following conclusions from the output above:<\/p>\n<ul>\n<li>The iteration 1 is the non-transformed query.<\/li>\n<li>The iteration 2 is the UNION ALL with three query blocks &#8211; one for each OR operand. At the end, this one had the lowest cost.<\/li>\n<li>The iteration 3 is the UNION ALL with two query blocks. The first query block contains the first OR operand P1 and the second query block has the second and the third operand (P2 OR P3).<\/li>\n<li>The iteration 4 is also the UNION ALL with two query blocks. The first query block entails the first and the second OR operand (P1 OR P2). The second query block contains the third OR operand P3. Unsurprisingly, the second query block wasn&#8217;t even costed since the first query block had already exceeded the cost of the second iteration.<\/li>\n<li>Interestingly, what wasn&#8217;t considered at all was the UNION ALL consisting of the state space = [{ 2 }] and state space = [{ 1 3 }], which, generally, could yield a good execution plan.<\/li>\n<\/ul>\n<p>Further, something strange will start happening if we keep adding more OR operators. For example, this is what we&#8217;ll get after the number of OR operands exceeds 4:<\/p>\n<pre><code>ORE: Starting iteration 1, state space = [{ 1 2 3 4 5 }]\nORE: Updated best state, Cost = 17.129661\nORE: Starting iteration 2, state space = [{ 1 }]\nORE: Updated best state, Cost = 2.000388\nORE: Starting iteration 2, state space = [{ 2 }]\nORE: Updated best state, Cost = 4.000776\nORE: Starting iteration 2, state space = [{ 3 }]\nORE: Updated best state, Cost = 6.001167\nORE: Starting iteration 2, state space = [{ 4 }]\nORE: Updated best state, Cost = 8.001558\nORE: Starting iteration 2, state space = [{ 5 }]\nORE: Updated best state, Cost = 10.001950\nORE:   Transferring best state space to preserved query. \nORE:   Transferring best state space to original query. <\/code><\/pre>\n<p>As you can see, the optimizer did only two iterations &#8211; one for the non-transformed query (iteration 1), and one for the UNION ALL query which has one query block for each OR-operand (iteration 2). I don&#8217;t know whether that&#8217;s an anomaly or some heuristics to limit time spent on calculating cost for different combinations.<\/p>\n<h1>Conjunction chains<\/h1>\n<p>We previously saw that the optimizer internally represents the OR operands with the conjunction chain matrix:<\/p>\n<pre><code>DNF Matrix (Before sorting OR branches)\n             P1  P2\nCNJ (#1) :   1   0\n\nCNJ (#2) :   0   1\n\nORE:  Predicate list\nP1 : \"T\".\"N1\"=1\nP2 : \"T\".\"N2\"=1<\/code><\/pre>\n<p>This might indeed seem unnecessary for our simple query. But it makes perfect sense for more complex WHERE clauses consisting of both OR and AND operators, like:<\/p>\n<pre><code>select  \/*+ OPT_PARAM('_B_TREE_BITMAP_PLANS','FALSE') *\/ \n  * from t where n1 = 1 <span style=\"color:green\">and n3 = 1<\/span> or n2 = 1 ;\n\n\nORE:  Predicate list\nP1 : \"T\".\"N1\"=1\n<span style=\"color:green\">P2 : \"T\".\"N3\"=1<\/span>\nP3 : \"T\".\"N2\"=1\n\n DNF Matrix (Before sorting OR branches)\n            P1  P2  P3\nCNJ (#1) :   1   <span style=\"color:green\">1<\/span>   0\n\nCNJ (#2) :   0   0   1\n\nORE:  Predicate list\nP1 : \"T\".\"N1\"=1\n<span style=\"color:green\">P2 : \"T\".\"N3\"=1<\/span>\nP3 : \"T\".\"N2\"=1\n\n DNF Matrix (After OR branch sorting)\n            P1  P2  P3\nCNJ (#1) :   0   0   1\n\nCNJ (#2) :   1   <span style=\"color:green\">1<\/span>   0<\/code><\/pre>\n<p>The purpose of this internal matrix representation becomes obvious now &#8211; it helps grouping the conjunctive operands together into a single OR operand.<\/p>\n<h1>Bugs<\/h1>\n<p>Although making ORE cost based generally leads to better executions plans, you should be aware of some boundary cases when it doesn&#8217;t function properly. I described one such example in my previous blog post <a href=\"https:\/\/nenadnoveljic.com\/blog\/cost-based-or-expansion-transformation\/\">Cost-Based OR Expansion Transformation<\/a>. There, you can also find how to fall back to pre-12.2 behavior in case you hit such problem.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Analyzing the CBO trace for getting insight into the cost based OR-expansion <a href=\"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/\" 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,33,5],"tags":[],"class_list":["post-2278","post","type-post","status-publish","format-standard","hentry","category-cost-based-optimizer","category-or-expansion","category-oracle"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Dissecting Cost Based OR-Expansion - All-round Database Topics<\/title>\n<meta name=\"description\" content=\"Analyzing the CBO trace for getting insight into the cost based OR-expansion\" \/>\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\/dissecting-cost-based-or-expansion\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Dissecting Cost Based OR-Expansion - All-round Database Topics\" \/>\n<meta property=\"og:description\" content=\"Analyzing the CBO trace for getting insight into the cost based OR-expansion\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/\" \/>\n<meta property=\"og:site_name\" content=\"All-round Database Topics\" \/>\n<meta property=\"article:published_time\" content=\"2018-12-05T21:29:17+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-10-02T16:43:48+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=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/\"},\"author\":{\"name\":\"Nenad Noveljic\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"headline\":\"Dissecting Cost Based OR-Expansion\",\"datePublished\":\"2018-12-05T21:29:17+00:00\",\"dateModified\":\"2020-10-02T16:43:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/\"},\"wordCount\":841,\"commentCount\":3,\"articleSection\":[\"cost based optimizer\",\"OR-expansion\",\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/\",\"name\":\"Dissecting Cost Based OR-Expansion - All-round Database Topics\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#website\"},\"datePublished\":\"2018-12-05T21:29:17+00:00\",\"dateModified\":\"2020-10-02T16:43:48+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"description\":\"Analyzing the CBO trace for getting insight into the cost based OR-expansion\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/dissecting-cost-based-or-expansion\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Dissecting Cost Based OR-Expansion\"}]},{\"@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":"Dissecting Cost Based OR-Expansion - All-round Database Topics","description":"Analyzing the CBO trace for getting insight into the cost based OR-expansion","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\/dissecting-cost-based-or-expansion\/","og_locale":"en_US","og_type":"article","og_title":"Dissecting Cost Based OR-Expansion - All-round Database Topics","og_description":"Analyzing the CBO trace for getting insight into the cost based OR-expansion","og_url":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/","og_site_name":"All-round Database Topics","article_published_time":"2018-12-05T21:29:17+00:00","article_modified_time":"2020-10-02T16:43:48+00:00","author":"Nenad Noveljic","twitter_card":"summary_large_image","twitter_creator":"@NenadNoveljic","twitter_misc":{"Written by":"Nenad Noveljic","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/#article","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/"},"author":{"name":"Nenad Noveljic","@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"headline":"Dissecting Cost Based OR-Expansion","datePublished":"2018-12-05T21:29:17+00:00","dateModified":"2020-10-02T16:43:48+00:00","mainEntityOfPage":{"@id":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/"},"wordCount":841,"commentCount":3,"articleSection":["cost based optimizer","OR-expansion","Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/","url":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/","name":"Dissecting Cost Based OR-Expansion - All-round Database Topics","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#website"},"datePublished":"2018-12-05T21:29:17+00:00","dateModified":"2020-10-02T16:43:48+00:00","author":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"description":"Analyzing the CBO trace for getting insight into the cost based OR-expansion","breadcrumb":{"@id":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/nenadnoveljic.com\/blog\/dissecting-cost-based-or-expansion\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nenadnoveljic.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Dissecting Cost Based OR-Expansion"}]},{"@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\/2278","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=2278"}],"version-history":[{"count":1,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2278\/revisions"}],"predecessor-version":[{"id":3566,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2278\/revisions\/3566"}],"wp:attachment":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/media?parent=2278"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/categories?post=2278"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/tags?post=2278"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}