{"id":2030,"date":"2018-06-20T19:50:14","date_gmt":"2018-06-20T19:50:14","guid":{"rendered":"http:\/\/nenadnoveljic.com\/blog\/?p=2030"},"modified":"2018-06-20T19:50:14","modified_gmt":"2018-06-20T19:50:14","slug":"first_rows-uncorrelated-subqueries","status":"publish","type":"post","link":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/","title":{"rendered":"first_rows Optimization in Uncorrelated Subqueries"},"content":{"rendered":"<p>This blog post is about suboptimal execution plans for uncorrelated subqueries involved in set operations. <\/p>\n<p>First of all, I&#8217;d like to give a short overview of three optimization modes: all_rows, first_rows(k) and first_rows. In doing so, I&#8217;ll use the following data set on a 12.2.0.1.180116 database:<\/p>\n<pre><code>\r\ncreate table t1 as select rownum n1 from dual \r\n  connect by level <= 100000 ;\r\n\r\ncreate table t2 as select rownum n1, mod(rownum,20000)+1 n2, lpad('A',3000,'A') c1  \r\n  from dual connect by level <= 100000 ; \r\n\r\nalter table t2 add constraint t2_pk primary key (n1) ;\r\n\r\ncreate index ix_t2_n2 on t2 (n2) ;\r\n<\/code><\/pre>\n<p>The column n1, which will be used for joining tables t1 and t2, contains consecutive integer values between 1 and 100000. The column t2.n2 contains uniformly distributed integer values between 1 and 20000.<\/p>\n<h1>all_rows<\/h1>\n<p>Because of the size of the tables, the optimizer prefers the hash join (HJ) to the nested loops (NL):<\/p>\n<pre><code>select \/*+ <span style=\"color:red\">all_rows<\/span>  *\/ 1\r\n  from t1 inner join t2 on t1.n1 = t2.n1 and t2.n2 = 10000 ;\r\n\r\n----------------------------------------------------------------------\r\n| Id  | Operation                    | Name     | Rows  | Cost (%CPU)|\r\n----------------------------------------------------------------------\r\n|   0 | SELECT STATEMENT             |          |       |    53 (100)|\r\n|*  1 |  <span style=\"color:red\">HASH JOIN<\/span>                   |          |     5 |    53   (2)|\r\n|   2 |   TABLE ACCESS BY INDEX ROWID| T2       |     5 |     6   (0)|\r\n|*  3 |    INDEX RANGE SCAN          | IX_T2_N2 |     5 |     1   (0)|\r\n|   4 |   TABLE ACCESS FULL          | T1       |   100K|    46   (0)|\r\n----------------------------------------------------------------------\r\n\r\nPredicate Information (identified by operation id):\r\n---------------------------------------------------\r\n\r\n   1 - access(\"T1\".\"N1\"=\"T2\".\"N1\")\r\n   <span style=\"color:red\">3 - access(\"T2\".\"N2\"=10000)<\/span>\r\n<\/code><\/pre>\n<h1>first_rows(k)<\/h1>\n<p>The first_rows(k) (a.k.a \"First K Rows\") optimization goal is to produce the execution plan for retrieving the first k rows as fast as possible. <\/p>\n<p>It's important to understand that the number of the estimated rows of the outer table in NL is the expected number of rows of the outer table that need to be fetched to return the first k rows. Therefore, this estimated cardinality is calculated as the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Expected_value\">expected value<\/a> of the fetched number of the outer table rows to find k matching rows in the inner table which fulfill the filter condition. Let k=1, this expected value can be calculated as follows:<\/p>\n<p>E = ( num_rows_inner + 1) \/ ( cardinality_inner + 1 )<\/p>\n<ul>\n<li>num_rows_inner is the total number of the inner table rows.<\/li>\n<li>cardinality_inner is the number of remaining rows of the inner table after applying the filter condition.<\/li>\n<\/ul>\n<p>In other words, the optimizer estimates how many unmatched outer table rows need to be fetched to find the first row in the inner table.<\/p>\n<p>This means, the less selective the predicate on the inner table, the higher the expected cardinality of the outer table, the higher the NL cost. <\/p>\n<p>Consequently, a less selective filter on the inner table is more likely to produce a HJ plan, such as:<\/p>\n<pre><code>select \/*+ <span style=\"color:red\">first_rows(1)<\/span>  *\/ 1\r\n  from t1 inner join t2 on t1.n1 = t2.n1 \r\n    and t2.n2 = 10000 ;\r\n  \r\n----------------------------------------------------------------------\r\n| Id  | Operation                    | Name     | Rows  | Cost (%CPU)|\r\n----------------------------------------------------------------------\r\n|   0 | SELECT STATEMENT             |          |       |    17 (100)|\r\n|*  1 |  <span style=\"color:red\">HASH JOIN<\/span>                   |          |     5 |    17   (0)|\r\n|   2 |   TABLE ACCESS BY INDEX ROWID| T2       |     5 |     6   (0)|\r\n|*  3 |    INDEX RANGE SCAN          | IX_T2_N2 |     5 |     1   (0)|\r\n|   4 |   TABLE ACCESS FULL          | T1       | 20129 |    11   (0)|\r\n----------------------------------------------------------------------\r\n\r\nPredicate Information (identified by operation id):\r\n---------------------------------------------------\r\n\r\n   1 - access(\"T1\".\"N1\"=\"T2\".\"N1\")\r\n   <span style=\"color:red\">3 - access(\"T2\".\"N2\"=1000)<\/span>\r\n<\/code><\/pre>\n<p>But if we replace the equality condition with a range the expected t1 cardinality will reach some tipping point where the execution plan will switch to NL:<\/p>\n<pre><code>select \/*+ first_rows(1)  *\/ 1\r\n  from t1 inner join t2 on t1.n1 = t2.n1 \r\n    and t2.n2 between 1 and 10000 ;\r\n\r\n-------------------------------------------------------------------\r\n| Id  | Operation                    | Name  | Rows  | Cost (%CPU)|\r\n-------------------------------------------------------------------\r\n|   0 | SELECT STATEMENT             |       |       |    42 (100)|\r\n|   1 |  NESTED LOOPS                |       |    40 |    42   (0)|\r\n|   2 |   <span style=\"color:red\">NESTED LOOPS<\/span>               |       |    40 |    42   (0)|\r\n|   3 |    TABLE ACCESS FULL         | T1    |    <span style=\"color:red\">40<\/span> |     2   (0)|\r\n|*  4 |    INDEX UNIQUE SCAN         | T2_PK |     1 |     0   (0)|\r\n|*  5 |   TABLE ACCESS BY INDEX ROWID| T2    |     1 |     1   (0)|\r\n-------------------------------------------------------------------\r\n\r\nPredicate Information (identified by operation id):\r\n---------------------------------------------------\r\n\r\n   4 - access(\"T1\".\"N1\"=\"T2\".\"N1\")\r\n   <span style=\"color:red\">5 - filter((\"T2\".\"N2\"<=1000 AND \"T2\".\"N2\">=1))<\/span><\/code><\/pre>\n<p>The optimizer estimated that in average <span style=\"color:red\">40<\/span> rows from t1 have to be fetched in order to find a matching row in t2 that fulfills the filter condition.<\/p>\n<p>The key point is that the optimizer runs a probability calculation to decide on the join method. In other words, the first_rows(k) optimization is fully cost based.<\/p>\n<p>By the way, the CBO trace provides a clue that the first_rows(k) optimization was done:<\/p>\n<pre><code>First K Rows: Setup begin\r\nFirst K Rows: K = 1.00, N = 5.00\r\nFirst K Rows: Setup end\r\nFirst K Rows: old pf = -1.0000000, new pf = 0.2012800\r\nSINGLE TABLE ACCESS PATH (First K Rows)\r\nFirst K Rows: old pf = -1.0000000, new pf = 1.0000000\r\nSINGLE TABLE ACCESS PATH (First K Rows)\r\nFirst K Rows: unchanged join prefix len = 1\r\nFirst K Rows: K = 1.00, N = 5.00\r\nFirst K Rows: old pf = 1.0000000, new pf = 0.2012900\r\nSINGLE TABLE ACCESS PATH (First K Rows)\r\nFirst K Rows: old pf = 0.2012800, new pf = 1.0000000\r\nSINGLE TABLE ACCESS PATH (First K Rows)\r\n...\r\nFinal cost for query block SEL$58A6D7F6 (#0) - <span style=\"color:red\">First K Rows Plan:<\/span><\/code><\/pre>\n<h1>first_rows<\/h1>\n<p>The first_rows optimization is partially rule based and therefore inferior to the first_rows(k) optimization. In fact, the <a href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/12.2\/refrn\/OPTIMIZER_MODE.html#GUID-DE448A8A-992F-4BAB-9302-A020039641E5\">Oracle database documentation<\/a> recommends to avoid it: \"FIRST_ROWS is available for backward compatibility and plan stability; use FIRST_ROWS_n instead.\"<\/p>\n<p>For instance, a suboptimal NL plan gets produced for the equal condition predicate, just because of some hard coded heuristics:<\/p>\n<pre><code>\r\nselect \/*+ <span style=\"color:red\">first_rows<\/span> *\/ 1\r\n  from t1 inner join t2 on t1.n1 = t2.n1 \r\n    and t2.n2 = 10000\r\n\r\n-------------------------------------------------------------------\r\n| Id  | Operation                    | Name  | Rows  | Cost (%CPU)|\r\n-------------------------------------------------------------------\r\n|   0 | SELECT STATEMENT             |       |       |   100K(100)|\r\n|   1 |  NESTED LOOPS                |       |     5 |   100K  (1)|\r\n|   2 |   <span style=\"color:red\">NESTED LOOPS<\/span>               |       |   100K|   100K  (1)|\r\n|   3 |    TABLE ACCESS FULL         | T1    |   100K|    46   (0)|\r\n|*  4 |    INDEX UNIQUE SCAN         | T2_PK |     1 |     0   (0)|\r\n|*  5 |   TABLE ACCESS BY INDEX ROWID| T2    |     1 |     1   (0)|\r\n-------------------------------------------------------------------\r\n\r\nPredicate Information (identified by operation id):\r\n---------------------------------------------------\r\n\r\n   4 - access(\"T1\".\"N1\"=\"T2\".\"N1\")\r\n   <span style=\"color:red\">5 - filter(\"T2\".\"N2\"=10000)<\/span>\r\n<\/code><\/pre>\n<p>Also in this case, the optimizer leaves a notice in the CBO trace that the first_rows optimization was performed:<\/p>\n<pre><code>Final cost for query block SEL$58A6D7F6 (#0) - <span style=\"color:red\">First Rows Plan:<\/span><\/code><\/pre>\n<p>As we shall see later, the optimizer can also switch optimization modes without being instructed to do so. So better remember the difference in the trace output between \"First Rows\" and \"First K Rows\" optimization, because it's good to know which one was effectively used when troubleshooting a bad execution plan.<\/p>\n<h1>Uncorrelated Subquery<\/h1>\n<p>Let's remove the hint in the previous query and use it to build an uncorrelated subquery:<\/p>\n<pre><code>select 1 from dual where <span style=\"color:red\">exists<\/span> (\r\n  select  1\r\n    from t1 inner join t2 on t1.n1 = t2.n1 \r\n      and t2.n2 = 10000) ;\r\n\r\n-----------------------------------------------------------------------------------------------------------------\r\n| Id  | Operation                     | Name     | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |\r\n-----------------------------------------------------------------------------------------------------------------\r\n|   0 | SELECT STATEMENT              |          |      1 |        |    19 (100)|      1 |00:00:00.01 |      25 |\r\n|*  1 |  FILTER                       |          |      1 |        |            |      1 |00:00:00.01 |      25 |\r\n|   2 |   FAST DUAL                   |          |      1 |      1 |     2   (0)|      1 |00:00:00.01 |       0 |\r\n|*  3 |   <span style=\"color:red\">HASH JOIN RIGHT SEMI<\/span>        |          |      1 |      5 |    17   (0)|      1 |00:00:00.01 |      <span style=\"color:red\">25<\/span>|\r\n|   4 |    TABLE ACCESS BY INDEX ROWID| T2       |      1 |      5 |     6   (0)|      5 |00:00:00.01 |       7 |\r\n|*  5 |     INDEX RANGE SCAN          | IX_T2_N2 |      1 |      5 |     1   (0)|      5 |00:00:00.01 |       2 |\r\n|   6 |    TABLE ACCESS FULL          | T1       |      1 |  20129 |    11   (0)|   9999 |00:00:00.01 |      18 |\r\n-----------------------------------------------------------------------------------------------------------------\r\n\r\nPredicate Information (identified by operation id):\r\n---------------------------------------------------\r\n\r\n   1 - filter( IS NOT NULL)\r\n   3 - access(\"T1\".\"N1\"=\"T2\".\"N1\")\r\n   <span style=\"color:red\">5 - access(\"T2\".\"N2\"=10000)<span style=\"color:red\">\r\n<\/code><\/pre>\n<p>Unsurprisingly, the optimizer produced a HJ plan for a non-selective equal condition filter. Furthermore, by looking into the CBO trace we can see that the optimizer implicitly used the \"First 1 Rows\" optimization for the uncorrelated subquery:<\/p>\n<pre><code>\r\nFirst K Rows: Setup begin\r\n<span style=\"color:red\">First K Rows: K = 1.00<\/span>, N = 5.00\r\nFirst K Rows: Setup end\r\nFirst K Rows: K = 1.00, N = 5.00\r\nFirst K Rows: old pf = -1.0000000, new pf = 0.2012800\r\nSINGLE TABLE ACCESS PATH (First K Rows)\r\nFirst K Rows: unchanged join prefix len = 1\r\nFirst K Rows: K = 1.00, N = 5.00\r\nFirst K Rows: old pf = 1.0000000, new pf = 0.2012900\r\n\r\nFinal cost for query block SEL$F1D6E378 (#2) - <span style=\"color:red\">First K Rows Plan:<\/span><\/code><\/pre>\n<p>In fact, that's a very smart optimization technique, as we're not interested in retrieving all of the rows - merely one row is sufficient for evaluating the exists subquery to TRUE. <\/p>\n<h1>Union<\/h1>\n<p>Unfortunately, the execution plan will change for worse if we add just a simple union:<\/p>\n<pre><code>\r\n<span style=\"color:red\">select 1 from dual\r\nunion<\/span>\r\nselect 1 from dual where exists (\r\n  select 1\r\n    from t1 inner join t2 on t1.n1 = t2.n1 \r\n      and t2.n2 = 10000 ) ;\r\n\r\n-------------------------------------------------------------------------------------------------------------------------\r\n| Id  | Operation                       | Name  | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers | Reads  |\r\n-------------------------------------------------------------------------------------------------------------------------\r\n|   0 | SELECT STATEMENT                |       |      1 |        |   100K(100)|      1 |00:00:00.14 |   10160 |   4752 |\r\n|   1 |  SORT UNIQUE                    |       |      1 |      2 |   100K  (1)|      1 |00:00:00.14 |   10160 |   4752 |\r\n|   2 |   UNION-ALL                     |       |      1 |        |            |      2 |00:00:00.14 |   10160 |   4752 |\r\n|   3 |    FAST DUAL                    |       |      1 |      1 |     2   (0)|      1 |00:00:00.01 |       0 |      0 |\r\n|*  4 |    FILTER                       |       |      1 |        |            |      1 |00:00:00.14 |   10160 |   4752 |\r\n|   5 |     FAST DUAL                   |       |      1 |      1 |     2   (0)|      1 |00:00:00.01 |       0 |      0 |\r\n|   6 |     <span style=\"color:red\">NESTED LOOPS SEMI<\/span>           |       |      1 |      5 |   100K  (1)|      1 |00:00:00.14 |   <span style=\"color:red\">10160<\/span> |   4752 |\r\n|   7 |      TABLE ACCESS FULL          | T1    |      1 |    100K|    46   (0)|   9999 |00:00:00.01 |      19 |      0 |\r\n|*  8 |      TABLE ACCESS BY INDEX ROWID| T2    |   9999 |      1 |     1   (0)|      1 |00:00:00.12 |   10141 |   4752 |\r\n|*  9 |       INDEX UNIQUE SCAN         | T2_PK |   9999 |      1 |     0   (0)|   9999 |00:00:00.01 |     142 |      0 |\r\n-------------------------------------------------------------------------------------------------------------------------\r\n\r\nPredicate Information (identified by operation id):\r\n---------------------------------------------------\r\n\r\n   4 - filter( IS NOT NULL)\r\n   <span style=\"color:red\">8 - filter(\"T2\".\"N2\"=10000)<\/span>\r\n   9 - access(\"T1\".\"N1\"=\"T2\".\"N1\")\r\n<\/code><\/pre>\n<p>As a consequence, the number of logical reads rocketed from just <span style=\"color:red\">25<\/span> to <span style=\"color:red\">10160<\/span>.<\/p>\n<p>This sudden change can be explained by looking into the CBO trace:<\/p>\n<pre><code>Final cost for query block SEL$5BF935F8 (#4) - <span style=\"color:red\">First Rows Plan:<\/span><\/code><\/pre>\n<p>I couldn't believe my eyes when I first saw that - the optimizer itself switched to the rule-based first_rows optimization. <\/p>\n<p>Obviously, there's still code around which implicitly optimizes for first_rows. So, you'll possibly need to hint the query to correct this behavior. <\/p>\n<p>For example, you might well decide that the all_rows plan is an acceptable compromise for your data set and filter predicates. In that case, you could embed the <span style=\"color:red\">first_rows(1)<\/span> hint into the query. The optimizer, however, won't take the hint - presumably because of the SORT UNIQUE operation, but it will silently switch to the all_rows mode:<\/p>\n<pre><code>\r\nselect \/*+ <span style=\"color:red\">first_rows(1)<\/span> *\/ 1 from dual\r\nunion\r\nselect 1 from dual where exists (\r\n  select 1\r\n    from t1 inner join t2 on t1.n1 = t2.n1 \r\n      and t2.n2 = 10000) ;\r\n\r\n-------------------------------------------------------------------------------------------------------------------\r\n| Id  | Operation                       | Name     | Starts | E-Rows | Cost (%CPU)| A-Rows |   A-Time   | Buffers |\r\n-------------------------------------------------------------------------------------------------------------------\r\n|   0 | SELECT STATEMENT                |          |      1 |        |    59 (100)|      1 |00:00:00.01 |      26 |\r\n|   1 |  SORT UNIQUE                    |          |      1 |      2 |    59   (6)|      1 |00:00:00.01 |      26 |\r\n|   2 |   UNION-ALL                     |          |      1 |        |            |      2 |00:00:00.01 |      26 |\r\n|   3 |    FAST DUAL                    |          |      1 |      1 |     2   (0)|      1 |00:00:00.01 |       0 |\r\n|*  4 |    FILTER                       |          |      1 |        |            |      1 |00:00:00.01 |      26 |\r\n|   5 |     FAST DUAL                   |          |      1 |      1 |     2   (0)|      1 |00:00:00.01 |       0 |\r\n|*  6 |     <span style=\"color:red\">HASH JOIN SEMI<\/span>              |          |      1 |      5 |    53   (2)|      1 |00:00:00.01 |      26 |\r\n|   7 |      TABLE ACCESS BY INDEX ROWID| T2       |      1 |      5 |     6   (0)|      5 |00:00:00.01 |       7 |\r\n|*  8 |       INDEX RANGE SCAN          | IX_T2_N2 |      1 |      5 |     1   (0)|      5 |00:00:00.01 |       2 |\r\n|   9 |      TABLE ACCESS FULL          | T1       |      1 |    100K|    46   (0)|   9999 |00:00:00.01 |      19 |\r\n-------------------------------------------------------------------------------------------------------------------\r\n\r\nPredicate Information (identified by operation id):\r\n---------------------------------------------------\r\n\r\n   4 - filter( IS NOT NULL)\r\n   6 - access(\"T1\".\"N1\"=\"T2\".\"N1\")\r\n   8 - access(\"T2\".\"N2\"=10000)\r\n<\/code><\/pre>\n<p>In contrast, hinting the subquery with all_rows doesn't have any impact on the optimization mode - the first_rows optimization will be used in this case.<\/p>\n<p>Am I the only one who finds it strange that you need to use the first_rows(1) hint to enforce the all_rows optimization?<\/p>\n<h1>References:<\/h1>\n<p><a href=\"https:\/\/jonathanlewis.wordpress.com\/2008\/11\/11\/first_rows_n\/\">first_rows_n<\/a>, <a href=\"https:\/\/jonathanlewis.wordpress.com\/\">Jonathan Lewis<\/a><br \/>\n<a href=\"http:\/\/www.stat.yale.edu\/~pollard\/Courses\/251.spring04\/Handouts\/Expectation.pdf\">Expectations<\/a>, David Pollard<br \/>\n<a href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/12.2\/refrn\/OPTIMIZER_MODE.html#GUID-DE448A8A-992F-4BAB-9302-A020039641E5\">Database Reference 12c Release 2 (12.2)<\/a>, Oracle Corp.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Suboptimal execution plans can be generated for uncorrelated subqueries involved in set operations.  <a href=\"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/\" 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,5],"tags":[],"class_list":["post-2030","post","type-post","status-publish","format-standard","hentry","category-cost-based-optimizer","category-oracle"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>first_rows Optimization in Uncorrelated Subqueries - All-round Database Topics<\/title>\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\/first_rows-uncorrelated-subqueries\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"first_rows Optimization in Uncorrelated Subqueries - All-round Database Topics\" \/>\n<meta property=\"og:description\" content=\"Suboptimal execution plans can be generated for uncorrelated subqueries involved in set operations. Continue Reading &rarr;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/\" \/>\n<meta property=\"og:site_name\" content=\"All-round Database Topics\" \/>\n<meta property=\"article:published_time\" content=\"2018-06-20T19:50:14+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<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/\"},\"author\":{\"name\":\"Nenad Noveljic\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"headline\":\"first_rows Optimization in Uncorrelated Subqueries\",\"datePublished\":\"2018-06-20T19:50:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/\"},\"wordCount\":864,\"commentCount\":2,\"articleSection\":[\"cost based optimizer\",\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/\",\"url\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/\",\"name\":\"first_rows Optimization in Uncorrelated Subqueries - All-round Database Topics\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#website\"},\"datePublished\":\"2018-06-20T19:50:14+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/#\\\/schema\\\/person\\\/51458d9dd86dbbdd19f5add451d44efa\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/first_rows-uncorrelated-subqueries\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nenadnoveljic.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"first_rows Optimization in Uncorrelated Subqueries\"}]},{\"@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":"first_rows Optimization in Uncorrelated Subqueries - All-round Database Topics","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\/first_rows-uncorrelated-subqueries\/","og_locale":"en_US","og_type":"article","og_title":"first_rows Optimization in Uncorrelated Subqueries - All-round Database Topics","og_description":"Suboptimal execution plans can be generated for uncorrelated subqueries involved in set operations. Continue Reading &rarr;","og_url":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/","og_site_name":"All-round Database Topics","article_published_time":"2018-06-20T19:50:14+00:00","author":"Nenad Noveljic","twitter_card":"summary_large_image","twitter_creator":"@NenadNoveljic","twitter_misc":{"Written by":"Nenad Noveljic"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/#article","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/"},"author":{"name":"Nenad Noveljic","@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"headline":"first_rows Optimization in Uncorrelated Subqueries","datePublished":"2018-06-20T19:50:14+00:00","mainEntityOfPage":{"@id":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/"},"wordCount":864,"commentCount":2,"articleSection":["cost based optimizer","Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/","url":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/","name":"first_rows Optimization in Uncorrelated Subqueries - All-round Database Topics","isPartOf":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#website"},"datePublished":"2018-06-20T19:50:14+00:00","author":{"@id":"https:\/\/nenadnoveljic.com\/blog\/#\/schema\/person\/51458d9dd86dbbdd19f5add451d44efa"},"breadcrumb":{"@id":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/nenadnoveljic.com\/blog\/first_rows-uncorrelated-subqueries\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nenadnoveljic.com\/blog\/"},{"@type":"ListItem","position":2,"name":"first_rows Optimization in Uncorrelated Subqueries"}]},{"@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\/2030","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=2030"}],"version-history":[{"count":1,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2030\/revisions"}],"predecessor-version":[{"id":2070,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/posts\/2030\/revisions\/2070"}],"wp:attachment":[{"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/media?parent=2030"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/categories?post=2030"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nenadnoveljic.com\/blog\/wp-json\/wp\/v2\/tags?post=2030"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}