List:Commits« Previous MessageNext Message »
From:Jorgen Loland Date:October 7 2010 9:02am
Subject:bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219) WL#5594
View as plain text  
#At file:///export/home/jl208045/mysql/wl4800/mysql-next-mr-opt-backporting-wl4800-patchcleanup/ based on revid:guilhem@stripped

 3219 Jorgen Loland	2010-10-07
      WL#5594 - Add optimizer traces to the range optimizer
      
      Add optimizer trace points to the range optimizer.
     @ mysql-test/include/optimizer_trace.inc
        Added tests to cover range optimizer
     @ mysql-test/r/optimizer_trace_no_prot.result
        Added tests to cover range optimizer. Also adds range information to trace of existing queries
     @ sql/handler.cc
        Add tracepoints to range optimizer
     @ sql/opt_range.cc
        Add tracepoints to range optimizer
     @ sql/opt_range.h
        Add tracepoints to range optimizer
     @ sql/sql_select.cc
        Add tracepoints to range optimizer

    modified:
      mysql-test/include/optimizer_trace.inc
      mysql-test/r/optimizer_trace_no_prot.result
      sql/handler.cc
      sql/opt_range.cc
      sql/opt_range.h
      sql/sql_select.cc
=== modified file 'mysql-test/include/optimizer_trace.inc'
--- a/mysql-test/include/optimizer_trace.inc	2010-10-05 10:29:43 +0000
+++ b/mysql-test/include/optimizer_trace.inc	2010-10-07 09:02:31 +0000
@@ -473,4 +473,138 @@ select 1 union select 2;
 
 drop table t1,t2;
 DROP TABLE C,D;
+
+set optimizer_trace=default;
+#################
+
+SET optimizer_trace="enabled=on,end_marker=off,one_line=off";
+
+CREATE TABLE t1
+(
+  key1 INT NOT NULL,
+  INDEX i1(key1)
+);
+
+--echo Inserting 1024 records into t1
+
+--disable_query_log
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8);
+
+let $1=7;
+set @d=8;
+while ($1)
+{
+  EVAL INSERT INTO t1 SELECT key1+@d FROM t1;
+  EVAL SET @d=@d*2;
+  DEC $1;
+}
+--enable_query_log
+
+ALTER TABLE t1 ADD key2 INT NOT NULL, ADD INDEX i2(key2);
+ALTER TABLE t1 ADD key3 INT NOT NULL, ADD INDEX i3(key3);
+ALTER TABLE t1 ADD key4 INT NOT NULL, ADD INDEX i4(key4);
+ALTER TABLE t1 ADD key5 INT NOT NULL, ADD INDEX i5(key5);
+ALTER TABLE t1 ADD key6 INT NOT NULL, ADD INDEX i6(key6);
+ALTER TABLE t1 ADD key7 INT NOT NULL, ADD INDEX i7(key7);
+ALTER TABLE t1 ADD key8 INT NOT NULL, ADD INDEX i8(key8);
+
+UPDATE t1 SET 
+  key2=key1,
+  key3=key1,
+  key4=key1,
+  key5=key1,
+  key6=key1,
+  key7=key1,
+  key8=1024-key1;
+
+CREATE TABLE t2 (
+  key1a INT NOT NULL,
+  key1b INT NOT NULL,
+  key2  INT NOT NULL,
+  key2_1 INT NOT NULL,
+  key2_2 INT NOT NULL,
+  key3  INT NOT NULL,
+  INDEX i1a (key1a, key1b),
+  INDEX i1b (key1b, key1a),
+  INDEX i2_1(key2, key2_1),
+  INDEX i2_2(key2, key2_1)
+);
+
+INSERT INTO t2 SELECT key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 FROM t1;
+
+# index merge
+--echo
+EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020;
+--echo
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+
+# group
+--echo
+EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2;
+--echo
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+
+#intersect
+--echo
+EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5);
+--echo
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+
+# union
+--echo 
+EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null;
+--echo
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+
+# range_scan_possible=false
+--echo
+EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2;    
+--echo
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+
+# more_expensive_than_table_scan
+--echo
+EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2  > 2);
+--echo
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+
+--echo
+
+DROP TABLE t1,t2;
+
+####
+
+CREATE TABLE t1 (
+  cola char(3) not null, 
+  colb char(3) not null,  
+  filler char(200),
+  key(cola), 
+  key(colb)
+) engine=innodb;
+INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ');
+
+--echo Inserting records
+--disable_query_log
+let $1=9;
+while ($1)
+{
+  eval INSERT INTO t1 SELECT * FROM t1 WHERE cola = 'foo';
+  dec $1;
+}
+LET $1=13;
+WHILE ($1)
+{
+  eval INSERT INTO t1 SELECT * FROM t1 WHERE cola <> 'foo';
+  dec $1;
+}
+
+--enable_query_log
+
+--echo
+EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar';
+--echo
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+
+DROP TABLE t1;
+
 set optimizer_trace=default;

=== modified file 'mysql-test/r/optimizer_trace_no_prot.result'
--- a/mysql-test/r/optimizer_trace_no_prot.result	2010-10-05 13:19:55 +0000
+++ b/mysql-test/r/optimizer_trace_no_prot.result	2010-10-07 09:02:31 +0000
@@ -41,6 +41,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "C"
             ],
             "records_estimation": [
+              {
+                "table": "C",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              }
             ]
           },
           {
@@ -80,9 +89,33 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                }
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  },
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ]
+                    }
+                  ],
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.4233,
+                    "chosen": true
+                  },
+                  "impossible_select": true,
+                  "stop_range_analysis": true,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  },
+                  "records": 0
+                },
+                "records": 0,
+                "cause": "impossible_where_condition"
               }
             ]
           }
@@ -97,18 +130,18 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
 select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
 from information_schema.OPTIMIZER_TRACE;
 (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
-44.4888
+49.1097
 set optimizer_trace="one_line=on";
 SELECT (SELECT 1 FROM D WHERE d = c) AS RESULT FROM C ;
 RESULT
 NULL
 select * from information_schema.OPTIMIZER_TRACE;
 QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_MEM_SIZE	OS_MALLOC_ERROR
-0	{"top_query": "SELECT (SELECT 1 FROM D WHERE d = c) AS RESULT FROM C","steps": [{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`D` where (`d` = `c`)) AS `RESULT` from `test`.`C`"},{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": []}}]}},{"join_optimization": {"select#": 1,"steps": [{"constant_tables": ["C"],"records_estimation": []},{"attaching_conditions_to_tables": {"original_condition": null,"attached_conditions": []}}]}},{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`D`.`d` = NULL)","after_equality_propagation": "multiple equal(NULL, `test`.`D`.`d`)","after_constant_propagation": "multiple equal(NULL, `test`.`D`.`d`)","after_trivial_conditions_removal": "multiple equal(NULL, `test`.`D`.`d`)"}},{"ref-optimizer-key-uses": [{"condition": "D.d= NULL","null_rejecting": true}]},{"constant_tables": [],"records_estimation": [{"ta
 ble": "D","more_range_optimizer_trace": {"TODO?": "yes!"}}]}],"empty_result": {"cause": "no matching row in const table"}}}]}	0	0
+0	{"top_query": "SELECT (SELECT 1 FROM D WHERE d = c) AS RESULT FROM C","steps": [{"expanded_query": "/* select#1 */ select (/* select#2 */ select 1 from `test`.`D` where (`d` = `c`)) AS `RESULT` from `test`.`C`"},{"join_preparation": {"select#": 1,"steps": [{"join_preparation": {"select#": 2,"steps": []}}]}},{"join_optimization": {"select#": 1,"steps": [{"constant_tables": ["C"],"records_estimation": [{"table": "C","found_records": 1,"records": 1,"cost": 1,"worst_seeks": 1,"exit_find_best_accessplan": true,"cause": "is_system_table"}]},{"attaching_conditions_to_tables": {"original_condition": null,"attached_conditions": []}}]}},{"join_optimization": {"select#": 2,"steps": [{"condition_processing": {"condition": "WHERE","original_condition": "(`test`.`D`.`d` = NULL)","after_equality_propagation": "multiple equal(NULL, `test`.`D`.`d`)","after_constant_propagation": "multiple equal(NULL, `test`.`D`.`d`)","after_trivial_conditions_removal": "multiple equal(NULL, `test`.`D`.`d`)
 "}},{"ref-optimizer-key-uses": [{"condition": "D.d= NULL","null_rejecting": true}]},{"constant_tables": [],"records_estimation": [{"table": "D","range_analysis": {"table_scan": {"records": 2,"cost": 4.5034},"potential_range_indices": [{"index": "d","key_parts": ["d"]}],"best_full_index_scan": {"index": "d","cost": 1.4233,"chosen": true},"impossible_select": true,"stop_range_analysis": true,"chosen_range_access_summary": {"chosen": false},"records": 0},"records": 0,"cause": "impossible_where_condition"}]}],"empty_result": {"cause": "no matching row in const table"}}}]}	0	0
 select (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
 from information_schema.OPTIMIZER_TRACE;
 (1-length(replace(TRACE, " ", ""))/length(TRACE))*100
-7.1942
+6.5983
 set optimizer_trace="one_line=off,end_marker=on";
 EXPLAIN SELECT (SELECT 1 FROM D WHERE d = ifnull(c,null)) AS RESULT FROM C ;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
@@ -145,6 +178,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "C"
             ] /* constant_tables */,
             "records_estimation": [
+              {
+                "table": "C",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              }
             ] /* records_estimation */
           },
           {
@@ -184,9 +226,33 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.4233,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "impossible_select": true,
+                  "stop_range_analysis": true,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 0
+                } /* range_analysis */,
+                "records": 0,
+                "cause": "impossible_where_condition"
               }
             ] /* records_estimation */
           }
@@ -232,6 +298,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "C"
             ] /* constant_tables */,
             "records_estimation": [
+              {
+                "table": "C",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              }
             ] /* records_estimation */
           },
           {
@@ -271,9 +346,33 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.4233,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "impossible_select": true,
+                  "stop_range_analysis": true,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 0
+                } /* range_analysis */,
+                "records": 0,
+                "cause": "impossible_where_condition"
               }
             ] /* records_estimation */
           }
@@ -338,6 +437,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "C"
             ] /* constant_tables */,
             "records_estimation": [
+              {
+                "table": "C",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              }
             ] /* records_estimation */
           },
           {
@@ -377,9 +485,33 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.4233,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "impossible_select": true,
+                  "stop_range_analysis": true,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 0
+                } /* range_analysis */,
+                "records": 0,
+                "cause": "impossible_where_condition"
               }
             ] /* records_estimation */
           }
@@ -416,9 +548,33 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.4233,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "impossible_select": true,
+                  "stop_range_analysis": true,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 0
+                } /* range_analysis */,
+                "records": 0,
+                "cause": "impossible_where_condition"
               }
             ] /* records_estimation */
           }
@@ -459,9 +615,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 10,
-                      "records": 0,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 0,
+                        "cost": 10
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -589,6 +749,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "C"
             ] /* constant_tables */,
             "records_estimation": [
+              {
+                "table": "C",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              }
             ] /* records_estimation */
           },
           {
@@ -676,9 +845,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                       "best_access_path": {
                         "considered_access_paths": [
                           {
-                            "access_type": "table scan",
-                            "cost": 10,
-                            "records": 0,
+                            "access_type": "scan",
+                            "using_range_access": false,
+                            "using_join_cache": true,
+                            "with_where_cond_processing": {
+                              "records": 0,
+                              "cost": 10
+                            } /* with_where_cond_processing */,
                             "chosen": true
                           }
                         ] /* considered_access_paths */
@@ -716,7 +889,7 @@ select (@trace:=TRACE)+NULL from informa
 NULL
 select length(@trace);
 length(@trace)
-8729
+9244
 set optimizer_trace_max_mem_size=8400;
 select length(@trace) > @@optimizer_trace_max_mem_size;
 length(@trace) > @@optimizer_trace_max_mem_size
@@ -725,13 +898,13 @@ SELECT * FROM C WHERE 5 IN (SELECT 1 FRO
 c
 select (@missing_bytes:=missing_bytes_beyond_max_mem_size) from information_schema.OPTIMIZER_TRACE;
 (@missing_bytes:=missing_bytes_beyond_max_mem_size)
-336
+852
 select (@trace2:=TRACE)+NULL from information_schema.OPTIMIZER_TRACE;
 (@trace2:=TRACE)+NULL
 NULL
 select length(@trace2), (length(@trace2) + @missing_bytes) = length(@trace);
 length(@trace2)	(length(@trace2) + @missing_bytes) = length(@trace)
-8393	1
+8392	1
 select length(@trace2) between (@@optimizer_trace_max_mem_size-100) and (@@optimizer_trace_max_mem_size+100);
 length(@trace2) between (@@optimizer_trace_max_mem_size-100) and (@@optimizer_trace_max_mem_size+100)
 1
@@ -808,10 +981,63 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             ] /* constant_tables */,
             "records_estimation": [
               {
+                "table": "C",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              },
+              {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.4233,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_single_table"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "d",
+                        "ranges": [
+                          "NULL <= d <= NULL"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 1,
+                        "cost": 2.21,
+                        "rowid_ordered": true,
+                        "chosen": false,
+                        "cause": "higher_cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_ror_intersect": {
+                      "usable": false,
+                      "cause": "too_few_ror_scans"
+                    } /* analyzing_ror_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 2
+                } /* range_analysis */
               }
             ] /* records_estimation */
           },
@@ -831,12 +1057,12 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                           {
                             "access_type": "index",
                             "index": "d",
-                            "cost": 1,
                             "records": 1,
+                            "cost": 1,
                             "chosen": true
                           },
                           {
-                            "access_type": "table scan",
+                            "access_type": "scan",
                             "cost": 2,
                             "records": 2,
                             "chosen": false
@@ -881,12 +1107,12 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     {
                       "access_type": "index",
                       "index": "d",
-                      "cost": 1,
                       "records": 1,
+                      "cost": 1,
                       "chosen": true
                     },
                     {
-                      "access_type": "table scan",
+                      "access_type": "scan",
                       "cost": 2,
                       "records": 2,
                       "chosen": false
@@ -1007,6 +1233,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "C"
             ] /* constant_tables */,
             "records_estimation": [
+              {
+                "table": "C",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              }
             ] /* records_estimation */
           },
           {
@@ -1054,9 +1289,53 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 2,
+                    "cost": 4.5034
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.4233,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "d",
+                        "ranges": [
+                          "NULL <= d <= NULL"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 1,
+                        "cost": 2.21,
+                        "rowid_ordered": true,
+                        "chosen": false,
+                        "cause": "higher_cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_ror_intersect": {
+                      "usable": false,
+                      "cause": "too_few_ror_scans"
+                    } /* analyzing_ror_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 2
+                } /* range_analysis */
               }
             ] /* records_estimation */
           },
@@ -1069,12 +1348,12 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     {
                       "access_type": "index",
                       "index": "d",
-                      "cost": 1,
                       "records": 1,
+                      "cost": 1,
                       "chosen": true
                     },
                     {
-                      "access_type": "table scan",
+                      "access_type": "scan",
                       "cost": 2,
                       "records": 2,
                       "chosen": false
@@ -1180,9 +1459,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0054,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0054
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1231,9 +1514,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0054,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0054
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1333,9 +1620,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0054,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0054
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1384,9 +1675,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0054,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0054
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1503,9 +1798,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0054,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0054
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1567,9 +1866,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0054,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0054
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1685,9 +1988,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0054,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0054
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1749,9 +2056,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0054,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0054
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1835,9 +2146,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0034,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0034
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1850,9 +2165,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     "best_access_path": {
                       "considered_access_paths": [
                         {
-                          "access_type": "table scan",
-                          "cost": 2.0053,
-                          "records": 3,
+                          "access_type": "scan",
+                          "using_range_access": false,
+                          "using_join_cache": true,
+                          "with_where_cond_processing": {
+                            "records": 3,
+                            "cost": 2.0053
+                          } /* with_where_cond_processing */,
                           "chosen": true
                         }
                       ] /* considered_access_paths */
@@ -1868,9 +2187,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -1883,9 +2206,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     "best_access_path": {
                       "considered_access_paths": [
                         {
-                          "access_type": "table scan",
-                          "cost": 2.0036,
-                          "records": 2,
+                          "access_type": "scan",
+                          "using_range_access": false,
+                          "using_join_cache": true,
+                          "with_where_cond_processing": {
+                            "records": 2,
+                            "cost": 2.0036
+                          } /* with_where_cond_processing */,
                           "chosen": true
                         }
                       ] /* considered_access_paths */
@@ -2118,9 +2445,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0293,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0293
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2182,9 +2513,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0293,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0293
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2316,9 +2651,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2331,9 +2670,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     "best_access_path": {
                       "considered_access_paths": [
                         {
-                          "access_type": "table scan",
-                          "cost": 2.0054,
-                          "records": 3,
+                          "access_type": "scan",
+                          "using_range_access": false,
+                          "using_join_cache": true,
+                          "with_where_cond_processing": {
+                            "records": 3,
+                            "cost": 2.0054
+                          } /* with_where_cond_processing */,
                           "chosen": true
                         }
                       ] /* considered_access_paths */
@@ -2349,9 +2692,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2417,9 +2764,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2508,9 +2859,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2572,9 +2927,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2630,9 +2989,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 10.05,
-                      "records": 1,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 1,
+                        "cost": 10.05
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2769,9 +3132,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2836,9 +3203,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2887,9 +3258,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0051,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -2950,6 +3325,24 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "t2"
             ] /* constant_tables */,
             "records_estimation": [
+              {
+                "table": "t1",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              },
+              {
+                "table": "t2",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              }
             ] /* records_estimation */
           },
           {
@@ -3066,6 +3459,33 @@ trace
             ] /* constant_tables */,
             "records_estimation": [
               {
+                "table": "t3",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              },
+              {
+                "table": "t1",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              },
+              {
+                "table": "t2",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              },
+              {
                 "table": "t4",
                 "table_scan": {
                   "records": 2,
@@ -3099,12 +3519,12 @@ trace
                     {
                       "access_type": "index",
                       "index": "PRIMARY",
-                      "cost": 1,
                       "records": 1,
+                      "cost": 1,
                       "chosen": true
                     },
                     {
-                      "access_type": "table scan",
+                      "access_type": "scan",
                       "cost": 2,
                       "records": 2,
                       "chosen": false
@@ -3171,6 +3591,33 @@ trace
             ] /* constant_tables */,
             "records_estimation": [
               {
+                "table": "t3",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              },
+              {
+                "table": "t1",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              },
+              {
+                "table": "t2",
+                "found_records": 1,
+                "records": 1,
+                "cost": 1,
+                "worst_seeks": 1,
+                "exit_find_best_accessplan": true,
+                "cause": "is_system_table"
+              },
+              {
                 "table": "t4",
                 "table_scan": {
                   "records": 2,
@@ -3188,12 +3635,12 @@ trace
                     {
                       "access_type": "index",
                       "index": "PRIMARY",
-                      "cost": 1,
                       "records": 1,
+                      "cost": 1,
                       "chosen": true
                     },
                     {
-                      "access_type": "table scan",
+                      "access_type": "scan",
                       "cost": 2,
                       "records": 2,
                       "chosen": false
@@ -3282,9 +3729,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0034,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0034
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -3297,9 +3748,12 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     "best_access_path": {
                       "considered_access_paths": [
                         {
-                          "access_type": "table scan",
-                          "cost": 4.0068,
-                          "records": 2,
+                          "access_type": "scan",
+                          "using_range_access": false,
+                          "with_where_cond_processing": {
+                            "records": 2,
+                            "cost": 4.0068
+                          } /* with_where_cond_processing */,
                           "chosen": true
                         }
                       ] /* considered_access_paths */
@@ -3422,9 +3876,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0044,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0044
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -3494,9 +3952,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0044,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0044
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -3595,10 +4057,15 @@ trace
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0044,
-                      "records": 2,
-                      "chosen": true
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0044
+                      } /* with_where_cond_processing */,
+                      "chosen": true,
+                      "use_temp_table": true
                     }
                   ] /* considered_access_paths */
                 } /* best_access_path */,
@@ -3610,9 +4077,13 @@ trace
                     "best_access_path": {
                       "considered_access_paths": [
                         {
-                          "access_type": "table scan",
-                          "cost": 2.0045,
-                          "records": 2,
+                          "access_type": "scan",
+                          "using_range_access": false,
+                          "using_join_cache": true,
+                          "with_where_cond_processing": {
+                            "records": 2,
+                            "cost": 2.0045
+                          } /* with_where_cond_processing */,
                           "chosen": true
                         }
                       ] /* considered_access_paths */
@@ -3628,9 +4099,13 @@ trace
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0044,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0044
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -3715,6 +4190,57 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
 0	{
   "top_query": "update D set d=5 where D is NULL",
   "steps": [
+    {
+      "range_analysis": {
+        "table_scan": {
+          "records": 2,
+          "cost": 4.5034
+        } /* table_scan */,
+        "potential_range_indices": [
+          {
+            "index": "d",
+            "key_parts": [
+              "d"
+            ] /* key_parts */
+          }
+        ] /* potential_range_indices */,
+        "group_index_range": {
+          "chosen": false,
+          "cause": "no_join"
+        } /* group_index_range */,
+        "analyzing_range_alternatives": {
+          "range_scan_alternatives": [
+            {
+              "index": "d",
+              "ranges": [
+                "NULL <= d <= NULL"
+              ] /* ranges */,
+              "index_only": false,
+              "records": 1,
+              "cost": 2.21,
+              "rowid_ordered": true,
+              "chosen": true
+            }
+          ] /* range_scan_alternatives */,
+          "analyzing_ror_intersect": {
+            "usable": false,
+            "cause": "too_few_ror_scans"
+          } /* analyzing_ror_intersect */
+        } /* analyzing_range_alternatives */,
+        "chosen_range_access_summary": {
+          "table_read_plan_type": "range_scan",
+          "index": "d",
+          "records": 1,
+          "ranges": [
+            "NULL <= d <= NULL"
+          ] /* ranges */,
+          "total_records": 1,
+          "total_cost": 2.21,
+          "chosen": true
+        } /* chosen_range_access_summary */,
+        "records": 1
+      } /* range_analysis */
+    }
   ] /* steps */
 }	0	0
 delete from D where d=5;
@@ -3725,6 +4251,53 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
   "steps": [
     {
       "expanded_query": "/* select#1 */ select  from dual where (`d` = 5)"
+    },
+    {
+      "range_analysis": {
+        "table_scan": {
+          "records": 2,
+          "cost": 4.5034
+        } /* table_scan */,
+        "potential_range_indices": [
+          {
+            "index": "d",
+            "key_parts": [
+              "d"
+            ] /* key_parts */
+          }
+        ] /* potential_range_indices */,
+        "group_index_range": {
+          "chosen": false,
+          "cause": "no_join"
+        } /* group_index_range */,
+        "analyzing_range_alternatives": {
+          "range_scan_alternatives": [
+            {
+              "index": "d",
+              "ranges": [
+                "5 <= d <= 5"
+              ] /* ranges */,
+              "index_only": false,
+              "records": 1,
+              "cost": 2.21,
+              "rowid_ordered": true,
+              "chosen": true
+            }
+          ] /* range_scan_alternatives */
+        } /* analyzing_range_alternatives */,
+        "chosen_range_access_summary": {
+          "table_read_plan_type": "range_scan",
+          "index": "d",
+          "records": 1,
+          "ranges": [
+            "5 <= d <= 5"
+          ] /* ranges */,
+          "total_records": 1,
+          "total_cost": 2.21,
+          "chosen": true
+        } /* chosen_range_access_summary */,
+        "records": 1
+      } /* range_analysis */
     }
   ] /* steps */
 }	0	0
@@ -3775,9 +4348,53 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 3,
+                    "cost": 4.7051
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.6465,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "d",
+                        "ranges": [
+                          "7 < d"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 2,
+                        "cost": 3.41,
+                        "rowid_ordered": false,
+                        "chosen": false,
+                        "cause": "higher_cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_ror_intersect": {
+                      "usable": false,
+                      "cause": "too_few_ror_scans"
+                    } /* analyzing_ror_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 3
+                } /* range_analysis */
               }
             ] /* records_estimation */
           },
@@ -3788,9 +4405,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.2051,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.2051
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -4009,9 +4630,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0154,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0154
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -4082,9 +4707,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0154,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0154
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -4152,9 +4781,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0154,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0154
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -4252,9 +4885,53 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 4,
+                    "cost": 4.9068
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.8698,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_single_table"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "d",
+                        "ranges": [
+                          "3 <= d <= 3"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 1,
+                        "cost": 2.21,
+                        "rowid_ordered": true,
+                        "chosen": false,
+                        "cause": "higher_cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_ror_intersect": {
+                      "usable": false,
+                      "cause": "too_few_ror_scans"
+                    } /* analyzing_ror_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 4
+                } /* range_analysis */
               },
               {
                 "table": "t2",
@@ -4279,9 +4956,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                       "best_access_path": {
                         "considered_access_paths": [
                           {
-                            "access_type": "table scan",
-                            "cost": 2.0212,
-                            "records": 3,
+                            "access_type": "scan",
+                            "using_range_access": false,
+                            "using_join_cache": true,
+                            "with_where_cond_processing": {
+                              "records": 3,
+                              "cost": 2.0212
+                            } /* with_where_cond_processing */,
                             "chosen": true
                           }
                         ] /* considered_access_paths */
@@ -4304,9 +4985,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0212,
-                      "records": 3,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 3,
+                        "cost": 2.0212
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -4323,14 +5008,18 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                         {
                           "access_type": "index",
                           "index": "d",
-                          "cost": 3,
                           "records": 1,
+                          "cost": 3,
                           "chosen": true
                         },
                         {
-                          "access_type": "table scan",
-                          "cost": 2.6076,
-                          "records": 1,
+                          "access_type": "scan",
+                          "using_range_access": false,
+                          "using_join_cache": true,
+                          "with_where_cond_processing": {
+                            "records": 1,
+                            "cost": 2.6076
+                          } /* with_where_cond_processing */,
                           "chosen": true
                         }
                       ] /* considered_access_paths */
@@ -4357,12 +5046,12 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     {
                       "access_type": "index",
                       "index": "d",
-                      "cost": 1,
                       "records": 1,
+                      "cost": 1,
                       "chosen": true
                     },
                     {
-                      "access_type": "table scan",
+                      "access_type": "scan",
                       "cost": 2,
                       "records": 4,
                       "chosen": false
@@ -4379,9 +5068,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     "best_access_path": {
                       "considered_access_paths": [
                         {
-                          "access_type": "table scan",
-                          "cost": 2.0213,
-                          "records": 3,
+                          "access_type": "scan",
+                          "using_range_access": false,
+                          "using_join_cache": true,
+                          "with_where_cond_processing": {
+                            "records": 3,
+                            "cost": 2.0213
+                          } /* with_where_cond_processing */,
                           "chosen": true
                         }
                       ] /* considered_access_paths */
@@ -4399,9 +5092,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                               "best_access_path": {
                                 "considered_access_paths": [
                                   {
-                                    "access_type": "table scan",
-                                    "cost": 2.0213,
-                                    "records": 3,
+                                    "access_type": "scan",
+                                    "using_range_access": false,
+                                    "using_join_cache": true,
+                                    "with_where_cond_processing": {
+                                      "records": 3,
+                                      "cost": 2.0213
+                                    } /* with_where_cond_processing */,
                                     "chosen": true
                                   }
                                 ] /* considered_access_paths */
@@ -4441,35 +5138,18 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "best_access_path": {
                 "considered_access_paths": [
                   {
-                    "access_type": "table scan",
-                    "cost": 2.0212,
-                    "records": 3,
+                    "access_type": "scan",
+                    "using_range_access": false,
+                    "with_where_cond_processing": {
+                      "records": 3,
+                      "cost": 2.0212
+                    } /* with_where_cond_processing */,
                     "chosen": true
                   }
                 ] /* considered_access_paths */
               } /* best_access_path */
             } /* reconsidering_access_paths_for_semijoin */
-          },
-          {
-            "attaching_conditions_to_tables": {
-              "original_condition": "((`test`.`D`.`d` = `f1`()) and (`test`.`t2`.`s` = 'c'))",
-              "attached_conditions": [
-                {
-                  "table": "D",
-                  "attached": "(`test`.`D`.`d` = `f1`())"
-                },
-                {
-                  "table": "t2",
-                  "attached": "((`test`.`D`.`d` = `f1`()) and (`test`.`t2`.`s` = 'c'))"
-                }
-              ] /* attached_conditions */
-            } /* attaching_conditions_to_tables */
-          }
-        ] /* steps */
-      } /* join_optimization */
-    }
-  ] /* steps */
-}	0	0
+          }	662	0
 0	{
   "top_query": "insert into t1 values(\"z\",0)",
   "steps": [
@@ -4480,6 +5160,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
   "steps": [
     {
       "expanded_query": "/* select#1 */ select  from dual where (`id` = 'z')"
+    },
+    {
+      "range_analysis": {
+        "table_scan": {
+          "records": 3,
+          "cost": 4.7154
+        } /* table_scan */,
+        "records": 3
+      } /* range_analysis */
     }
   ] /* steps */
 }	0	0
@@ -4520,35 +5209,8 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0154,
-                      "records": 2,
-                      "chosen": true
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 2.0154,
-                "records_for_plan": 2,
-                "chosen": true
-              }
-            ] /* considered_execution_plans */
-          },
-          {
-            "attaching_conditions_to_tables": {
-              "original_condition": null,
-              "attached_conditions": [
-                {
-                  "table": "t1",
-                  "attached": null
-                }
-              ] /* attached_conditions */
-            } /* attaching_conditions_to_tables */
-          }
-        ] /* steps */
-      } /* join_optimization */
-    }
-  ] /* steps */
-}	0	0
+                      "access_type": "scan",
+                      "using_range_access	1012	0
 set optimizer_trace_offset=2, optimizer_trace_limit=1|
 select * from D where d in (select f1() from t2 where s="c")|
 d
@@ -4559,6 +5221,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
   "steps": [
     {
       "expanded_query": "/* select#1 */ select  from dual where (`id` = 'z')"
+    },
+    {
+      "range_analysis": {
+        "table_scan": {
+          "records": 3,
+          "cost": 4.7154
+        } /* table_scan */,
+        "records": 3
+      } /* range_analysis */
     }
   ] /* steps */
 }	0	0
@@ -4614,9 +5285,33 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 4,
+                    "cost": 4.9068
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.8698,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "impossible_select": true,
+                  "stop_range_analysis": true,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 0
+                } /* range_analysis */,
+                "records": 0,
+                "cause": "impossible_where_condition"
               }
             ] /* records_estimation */
           }
@@ -4672,9 +5367,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0154,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0154
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -4765,9 +5464,33 @@ select @trace;
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 4,
+                    "cost": 4.9068
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.8698,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "impossible_select": true,
+                  "stop_range_analysis": true,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 0
+                } /* range_analysis */,
+                "records": 0,
+                "cause": "impossible_where_condition"
               }
             ] /* records_estimation */
           }
@@ -4869,9 +5592,53 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
             "records_estimation": [
               {
                 "table": "D",
-                "more_range_optimizer_trace": {
-                  "TODO?": "yes!"
-                } /* more_range_optimizer_trace */
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 4,
+                    "cost": 4.9068
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "d",
+                      "key_parts": [
+                        "d"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "best_full_index_scan": {
+                    "index": "d",
+                    "cost": 1.8698,
+                    "chosen": true
+                  } /* best_full_index_scan */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_single_table"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "d",
+                        "ranges": [
+                          "3 <= d <= 3"
+                        ] /* ranges */,
+                        "index_only": true,
+                        "records": 1,
+                        "cost": 2.21,
+                        "rowid_ordered": true,
+                        "chosen": false,
+                        "cause": "higher_cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_ror_intersect": {
+                      "usable": false,
+                      "cause": "too_few_ror_scans"
+                    } /* analyzing_ror_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  } /* chosen_range_access_summary */,
+                  "records": 4
+                } /* range_analysis */
               },
               {
                 "table": "t2",
@@ -4896,9 +5663,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                       "best_access_path": {
                         "considered_access_paths": [
                           {
-                            "access_type": "table scan",
-                            "cost": 2.0496,
-                            "records": 7,
+                            "access_type": "scan",
+                            "using_range_access": false,
+                            "using_join_cache": true,
+                            "with_where_cond_processing": {
+                              "records": 7,
+                              "cost": 2.0496
+                            } /* with_where_cond_processing */,
                             "chosen": true
                           }
                         ] /* considered_access_paths */
@@ -4923,12 +5694,12 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     {
                       "access_type": "index",
                       "index": "d",
-                      "cost": 1,
                       "records": 1,
+                      "cost": 1,
                       "chosen": true
                     },
                     {
-                      "access_type": "table scan",
+                      "access_type": "scan",
                       "cost": 2,
                       "records": 4,
                       "chosen": false
@@ -4945,9 +5716,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                     "best_access_path": {
                       "considered_access_paths": [
                         {
-                          "access_type": "table scan",
-                          "cost": 2.0496,
-                          "records": 7,
+                          "access_type": "scan",
+                          "using_range_access": false,
+                          "using_join_cache": true,
+                          "with_where_cond_processing": {
+                            "records": 7,
+                            "cost": 2.0496
+                          } /* with_where_cond_processing */,
                           "chosen": true
                         }
                       ] /* considered_access_paths */
@@ -4965,9 +5740,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                               "best_access_path": {
                                 "considered_access_paths": [
                                   {
-                                    "access_type": "table scan",
-                                    "cost": 2.0496,
-                                    "records": 7,
+                                    "access_type": "scan",
+                                    "using_range_access": false,
+                                    "using_join_cache": true,
+                                    "with_where_cond_processing": {
+                                      "records": 7,
+                                      "cost": 2.0496
+                                    } /* with_where_cond_processing */,
                                     "chosen": true
                                   }
                                 ] /* considered_access_paths */
@@ -5003,9 +5782,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0496,
-                      "records": 7,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 7,
+                        "cost": 2.0496
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -5025,35 +5808,18 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
               "best_access_path": {
                 "considered_access_paths": [
                   {
-                    "access_type": "table scan",
-                    "cost": 2.0496,
-                    "records": 7,
+                    "access_type": "scan",
+                    "using_range_access": false,
+                    "with_where_cond_processing": {
+                      "records": 7,
+                      "cost": 2.0496
+                    } /* with_where_cond_processing */,
                     "chosen": true
                   }
                 ] /* considered_access_paths */
               } /* best_access_path */
             } /* reconsidering_access_paths_for_semijoin */
-          },
-          {
-            "attaching_conditions_to_tables": {
-              "original_condition": "((`test`.`D`.`d` = `f1`()) and (`test`.`t2`.`s` = arg@0))",
-              "attached_conditions": [
-                {
-                  "table": "D",
-                  "attached": "(`test`.`D`.`d` = `f1`())"
-                },
-                {
-                  "table": "t2",
-                  "attached": "((`test`.`D`.`d` = `f1`()) and (`test`.`t2`.`s` = arg@0))"
-                }
-              ] /* attached_conditions */
-            } /* attaching_conditions_to_tables */
-          }
-        ] /* steps */
-      } /* join_optimization */
-    }
-  ] /* steps */
-}	0	0
+          }	666	0
 0	{
   "top_query": "insert into t1 values(\"z\",0)",
   "steps": [
@@ -5064,6 +5830,15 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
   "steps": [
     {
       "expanded_query": "/* select#1 */ select  from dual where (`id` = 'z')"
+    },
+    {
+      "range_analysis": {
+        "table_scan": {
+          "records": 3,
+          "cost": 4.7154
+        } /* table_scan */,
+        "records": 3
+      } /* range_analysis */
     }
   ] /* steps */
 }	0	0
@@ -5104,40 +5879,11 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0154,
-                      "records": 2,
-                      "chosen": true
-                    }
-                  ] /* considered_access_paths */
-                } /* best_access_path */,
-                "cost_for_plan": 2.0154,
-                "records_for_plan": 2,
-                "chosen": true
-              }
-            ] /* considered_execution_plans */
-          },
-          {
-            "attaching_conditions_to_tables": {
-              "original_condition": null,
-              "attached_conditions": [
-                {
-                  "table": "t1",
-                  "attached": null
-                }
-              ] /* attached_conditions */
-            } /* attaching_conditions_to_tables */
-          }
-        ] /* steps */
-      } /* join_optimization */
-    }
-  ] /* steps */
-}	0	0
-0	{
-  "top_query": "SET optimizer_trace=\"enabled=off\"",
-  "steps": [
-  ] /* steps */
-}	0	0
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing	905	0
+0		84	0
 select @@optimizer_trace|
 @@optimizer_trace
 enabled=off,end_marker=on,one_line=off
@@ -5210,9 +5956,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0154,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0154
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -5305,9 +6055,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 2.0154,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 2.0154
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -5376,9 +6130,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 10.1,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 10.1
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -5462,9 +6220,13 @@ QUERY_ID	TRACE	MISSING_BYTES_BEYOND_MAX_
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 10.1,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 10.1
+                      } /* with_where_cond_processing */,
                       "chosen": true
                     }
                   ] /* considered_access_paths */
@@ -5562,9 +6324,13 @@ select TRACE into dumpfile 'MYSQLTEST_VA
                 "best_access_path": {
                   "considered_access_paths": [
                     {
-                      "access_type": "table scan",
-                      "cost": 10.1,
-                      "records": 2,
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 10.1
+                      },
                       "chosen": true
                     }
                   ]
@@ -5593,3 +6359,1365 @@ select TRACE into dumpfile 'MYSQLTEST_VA
 }drop table t1,t2;
 DROP TABLE C,D;
 set optimizer_trace=default;
+SET optimizer_trace="enabled=on,end_marker=off,one_line=off";
+CREATE TABLE t1
+(
+key1 INT NOT NULL,
+INDEX i1(key1)
+);
+Inserting 1024 records into t1
+ALTER TABLE t1 ADD key2 INT NOT NULL, ADD INDEX i2(key2);
+ALTER TABLE t1 ADD key3 INT NOT NULL, ADD INDEX i3(key3);
+ALTER TABLE t1 ADD key4 INT NOT NULL, ADD INDEX i4(key4);
+ALTER TABLE t1 ADD key5 INT NOT NULL, ADD INDEX i5(key5);
+ALTER TABLE t1 ADD key6 INT NOT NULL, ADD INDEX i6(key6);
+ALTER TABLE t1 ADD key7 INT NOT NULL, ADD INDEX i7(key7);
+ALTER TABLE t1 ADD key8 INT NOT NULL, ADD INDEX i8(key8);
+UPDATE t1 SET 
+key2=key1,
+key3=key1,
+key4=key1,
+key5=key1,
+key6=key1,
+key7=key1,
+key8=1024-key1;
+CREATE TABLE t2 (
+key1a INT NOT NULL,
+key1b INT NOT NULL,
+key2  INT NOT NULL,
+key2_1 INT NOT NULL,
+key2_2 INT NOT NULL,
+key3  INT NOT NULL,
+INDEX i1a (key1a, key1b),
+INDEX i1b (key1b, key1a),
+INDEX i2_1(key2, key2_1),
+INDEX i2_2(key2, key2_1)
+);
+INSERT INTO t2 SELECT key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 FROM t1;
+
+EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	index_merge	i1,i2	i1,i2	4,4	NULL	45	Using sort_union(i1,i2); Using where
+
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+TRACE
+{
+  "top_query": "EXPLAIN SELECT * FROM t1 WHERE key1 < 3 OR key2 > 1020",
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`key1` < 3) or (`key2` > 1020))"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))",
+              "after_equality_propagation": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))",
+              "after_constant_propagation": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))",
+              "after_trivial_conditions_removal": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))"
+            }
+          },
+          {
+            "ref-optimizer-key-uses": [
+            ]
+          },
+          {
+            "constant_tables": [
+            ],
+            "records_estimation": [
+              {
+                "table": "t1",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 1024,
+                    "cost": 217.15
+                  },
+                  "potential_range_indices": [
+                    {
+                      "index": "i1",
+                      "key_parts": [
+                        "key1"
+                      ]
+                    },
+                    {
+                      "index": "i2",
+                      "key_parts": [
+                        "key2"
+                      ]
+                    },
+                    {
+                      "index": "i3",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i4",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i5",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i6",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i7",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i8",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    }
+                  ],
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  },
+                  "analyzing_index_merge": [
+                    {
+                      "indices_to_merge": [
+                        {
+                          "range_scan_alternatives": [
+                            {
+                              "index": "i1",
+                              "ranges": [
+                                "key1 < 3"
+                              ],
+                              "index_only": true,
+                              "records": 3,
+                              "cost": 1.6526,
+                              "rowid_ordered": false,
+                              "chosen": true
+                            }
+                          ],
+                          "index_to_merge": "i1",
+                          "new_cost": 1.6526
+                        },
+                        {
+                          "range_scan_alternatives": [
+                            {
+                              "index": "i2",
+                              "ranges": [
+                                "1020 < key2"
+                              ],
+                              "index_only": true,
+                              "records": 42,
+                              "cost": 10.282,
+                              "rowid_ordered": false,
+                              "chosen": true
+                            }
+                          ],
+                          "index_to_merge": "i2",
+                          "new_cost": 11.935
+                        }
+                      ],
+                      "scan_cost": 11.935,
+                      "total_cost": 58.363
+                    }
+                  ],
+                  "chosen_range_access_summary": {
+                    "table_read_plan_type": "index_merge",
+                    "index_merge_of": [
+                      {
+                        "table_read_plan_type": "range_scan",
+                        "index": "i1",
+                        "records": 3,
+                        "ranges": [
+                          "key1 < 3"
+                        ]
+                      },
+                      {
+                        "table_read_plan_type": "range_scan",
+                        "index": "i2",
+                        "records": 42,
+                        "ranges": [
+                          "1020 < key2"
+                        ]
+                      }
+                    ],
+                    "total_records": 45,
+                    "total_cost": 58.363,
+                    "chosen": true
+                  },
+                  "records": 45
+                }
+              }
+            ]
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "table": "t1",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_range_access": true,
+                      "with_where_cond_processing": {
+                        "records": 45,
+                        "cost": 58.363
+                      },
+                      "chosen": true
+                    }
+                  ]
+                },
+                "cost_for_plan": 58.363,
+                "records_for_plan": 45,
+                "chosen": true
+              }
+            ]
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))",
+              "attached_conditions": [
+                {
+                  "table": "t1",
+                  "attached": "((`test`.`t1`.`key1` < 3) or (`test`.`t1`.`key2` > 1020))"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
+
+EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t2	range	NULL	i2_1	4	NULL	103	Using index for group-by
+
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+TRACE
+{
+  "top_query": "EXPLAIN SELECT key2, MIN(key2_1) FROM t2 GROUP BY key2",
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `key2` AS `key2`,min(`key2_1`) AS `MIN(key2_1)` from `test`.`t2` group by `key2`"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "constant_tables": [
+            ],
+            "records_estimation": [
+              {
+                "table": "t2",
+                "const_keys_added": {
+                  "keys": [
+                    "i2_1",
+                    "i2_2"
+                  ],
+                  "cause": "group_by"
+                },
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 1024,
+                    "cost": 215.15
+                  },
+                  "potential_range_indices": [
+                    {
+                      "index": "i1a",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i1b",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i2_1",
+                      "key_parts": [
+                        "key2",
+                        "key2_1"
+                      ]
+                    },
+                    {
+                      "index": "i2_2",
+                      "key_parts": [
+                        "key2",
+                        "key2_1"
+                      ]
+                    }
+                  ],
+                  "best_full_index_scan": {
+                    "index": "i2_1",
+                    "cost": 235.03,
+                    "chosen": false
+                  },
+                  "group_index_range": {
+                    "potential_group_range_indices": [
+                      {
+                        "index": "i1a",
+                        "usable": false,
+                        "covering_index": false
+                      },
+                      {
+                        "index": "i1b",
+                        "usable": false,
+                        "covering_index": false
+                      },
+                      {
+                        "index": "i2_1",
+                        "covering": true,
+                        "records": 103,
+                        "cost": 50.6
+                      },
+                      {
+                        "index": "i2_2",
+                        "covering": true,
+                        "records": 103,
+                        "cost": 50.6
+                      }
+                    ]
+                  },
+                  "best_group_range_summary": {
+                    "table_read_plan_type": "index_group",
+                    "index": "i2_1",
+                    "records": 103,
+                    "cost": 50.6
+                  },
+                  "chosen_range_access_summary": {
+                    "table_read_plan_type": "index_group",
+                    "index": "i2_1",
+                    "records": 103,
+                    "cost": 50.6,
+                    "total_records": 103,
+                    "total_cost": 50.6,
+                    "chosen": true
+                  },
+                  "records": 103
+                }
+              }
+            ]
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "table": "t2",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_range_access": true,
+                      "with_where_cond_processing": {
+                        "records": 103,
+                        "cost": 50.6
+                      },
+                      "chosen": true,
+                      "use_temp_table": true
+                    }
+                  ]
+                },
+                "cost_for_plan": 50.6,
+                "records_for_plan": 103,
+                "chosen": true
+              }
+            ]
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": null,
+              "attached_conditions": [
+                {
+                  "table": "t2",
+                  "attached": null
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
+
+EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t2	ref	i2_1,i2_2	i2_1	4	const	10	Using where
+
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+TRACE
+{
+  "top_query": "EXPLAIN SELECT * FROM t2 WHERE key2 = 1 AND (key2_1 = 1 OR key3 = 5)",
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t2` where ((`key2` = 1) and ((`key2_1` = 1) or (`key3` = 5)))"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`test`.`t2`.`key2` = 1) and ((`test`.`t2`.`key2_1` = 1) or (`test`.`t2`.`key3` = 5)))",
+              "after_equality_propagation": "((multiple equal(1, `test`.`t2`.`key2_1`) or multiple equal(5, `test`.`t2`.`key3`)) and multiple equal(1, `test`.`t2`.`key2`))",
+              "after_constant_propagation": "((multiple equal(1, `test`.`t2`.`key2_1`) or multiple equal(5, `test`.`t2`.`key3`)) and multiple equal(1, `test`.`t2`.`key2`))",
+              "after_trivial_conditions_removal": "((multiple equal(1, `test`.`t2`.`key2_1`) or multiple equal(5, `test`.`t2`.`key3`)) and multiple equal(1, `test`.`t2`.`key2`))"
+            }
+          },
+          {
+            "ref-optimizer-key-uses": [
+              {
+                "condition": "t2.key2= 1",
+                "null_rejecting": false
+              },
+              {
+                "condition": "t2.key2= 1",
+                "null_rejecting": false
+              }
+            ]
+          },
+          {
+            "constant_tables": [
+            ],
+            "records_estimation": [
+              {
+                "table": "t2",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 1024,
+                    "cost": 215.15
+                  },
+                  "potential_range_indices": [
+                    {
+                      "index": "i1a",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i1b",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i2_1",
+                      "key_parts": [
+                        "key2",
+                        "key2_1"
+                      ]
+                    },
+                    {
+                      "index": "i2_2",
+                      "key_parts": [
+                        "key2",
+                        "key2_1"
+                      ]
+                    }
+                  ],
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  },
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "i2_1",
+                        "ranges": [
+                          "1 <= key2 <= 1"
+                        ],
+                        "index_only": false,
+                        "records": 10,
+                        "cost": 13.01,
+                        "rowid_ordered": false,
+                        "chosen": true
+                      },
+                      {
+                        "index": "i2_2",
+                        "ranges": [
+                          "1 <= key2 <= 1"
+                        ],
+                        "index_only": false,
+                        "records": 10,
+                        "cost": 13.01,
+                        "rowid_ordered": false,
+                        "chosen": false,
+                        "cause": "higher_cost"
+                      }
+                    ],
+                    "analyzing_ror_intersect": {
+                      "usable": false,
+                      "cause": "too_few_ror_scans"
+                    }
+                  },
+                  "chosen_range_access_summary": {
+                    "table_read_plan_type": "range_scan",
+                    "index": "i2_1",
+                    "records": 10,
+                    "ranges": [
+                      "1 <= key2 <= 1"
+                    ],
+                    "total_records": 10,
+                    "total_cost": 13.01,
+                    "chosen": true
+                  },
+                  "records": 10
+                }
+              }
+            ]
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "table": "t2",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "index",
+                      "index": "i2_1",
+                      "records": 10,
+                      "cost": 10,
+                      "chosen": true
+                    },
+                    {
+                      "access_type": "index",
+                      "index": "i2_2",
+                      "records": 10,
+                      "cost": 10,
+                      "chosen": false
+                    },
+                    {
+                      "access_type": "scan",
+                      "chosen": false,
+                      "cause": "heuristic_index_cheaper"
+                    }
+                  ]
+                },
+                "cost_for_plan": 10,
+                "records_for_plan": 10,
+                "chosen": true
+              }
+            ]
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`test`.`t2`.`key2` = 1) and ((`test`.`t2`.`key2_1` = 1) or (`test`.`t2`.`key3` = 5)))",
+              "attached_conditions": [
+                {
+                  "table": "t2",
+                  "attached": "((`test`.`t2`.`key2_1` = 1) or (`test`.`t2`.`key3` = 5))"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
+
+EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	index_merge	i2,i3,i4	i2,i3	4,4	NULL	2	Using union(i2,i3); Using where
+
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+TRACE
+{
+  "top_query": "EXPLAIN SELECT * FROM t1 WHERE key2=10 OR key3=3 OR key4 <=> null",
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`key2` = 10) or (`key3` = 3) or (`key4` <=> NULL))"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`test`.`t1`.`key2` = 10) or (`test`.`t1`.`key3` = 3) or (`test`.`t1`.`key4` <=> NULL))",
+              "after_equality_propagation": "(multiple equal(10, `test`.`t1`.`key2`) or multiple equal(3, `test`.`t1`.`key3`) or (`test`.`t1`.`key4` <=> NULL))",
+              "after_constant_propagation": "(multiple equal(10, `test`.`t1`.`key2`) or multiple equal(3, `test`.`t1`.`key3`) or (`test`.`t1`.`key4` <=> NULL))",
+              "after_trivial_conditions_removal": "(multiple equal(10, `test`.`t1`.`key2`) or multiple equal(3, `test`.`t1`.`key3`) or (`test`.`t1`.`key4` <=> NULL))"
+            }
+          },
+          {
+            "ref-optimizer-key-uses": [
+            ]
+          },
+          {
+            "constant_tables": [
+            ],
+            "records_estimation": [
+              {
+                "table": "t1",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 1024,
+                    "cost": 217.15
+                  },
+                  "potential_range_indices": [
+                    {
+                      "index": "i1",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i2",
+                      "key_parts": [
+                        "key2"
+                      ]
+                    },
+                    {
+                      "index": "i3",
+                      "key_parts": [
+                        "key3"
+                      ]
+                    },
+                    {
+                      "index": "i4",
+                      "key_parts": [
+                        "key4"
+                      ]
+                    },
+                    {
+                      "index": "i5",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i6",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i7",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i8",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    }
+                  ],
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  },
+                  "analyzing_index_merge": [
+                    {
+                      "indices_to_merge": [
+                        {
+                          "range_scan_alternatives": [
+                            {
+                              "index": "i2",
+                              "ranges": [
+                                "10 <= key2 <= 10"
+                              ],
+                              "index_only": true,
+                              "records": 1,
+                              "cost": 2.21,
+                              "rowid_ordered": true,
+                              "chosen": true
+                            }
+                          ],
+                          "index_to_merge": "i2",
+                          "new_cost": 2.21
+                        },
+                        {
+                          "range_scan_alternatives": [
+                            {
+                              "index": "i3",
+                              "ranges": [
+                                "3 <= key3 <= 3"
+                              ],
+                              "index_only": true,
+                              "records": 1,
+                              "cost": 2.21,
+                              "rowid_ordered": true,
+                              "chosen": true
+                            }
+                          ],
+                          "index_to_merge": "i3",
+                          "new_cost": 4.42
+                        }
+                      ],
+                      "scan_cost": 4.42,
+                      "use_ror_union": true,
+                      "cause": "always_cheaper_than_non_ror",
+                      "analyzing_ror_scans": [
+                        {
+                          "table_read_plan_type": "range_scan",
+                          "index": "i2",
+                          "records": 1,
+                          "ranges": [
+                            "10 <= key2 <= 10"
+                          ],
+                          "analyzing_ror_intersect": {
+                            "usable": false,
+                            "cause": "too_few_ror_scans"
+                          }
+                        },
+                        {
+                          "table_read_plan_type": "range_scan",
+                          "index": "i3",
+                          "records": 1,
+                          "ranges": [
+                            "3 <= key3 <= 3"
+                          ],
+                          "analyzing_ror_intersect": {
+                            "usable": false,
+                            "cause": "too_few_ror_scans"
+                          }
+                        }
+                      ],
+                      "index_roworder_union_cost": 6.327,
+                      "members": 2,
+                      "chosen": true
+                    }
+                  ],
+                  "chosen_range_access_summary": {
+                    "table_read_plan_type": "index_roworder_union",
+                    "union_of": [
+                      {
+                        "table_read_plan_type": "range_scan",
+                        "index": "i2",
+                        "records": 1,
+                        "ranges": [
+                          "10 <= key2 <= 10"
+                        ]
+                      },
+                      {
+                        "table_read_plan_type": "range_scan",
+                        "index": "i3",
+                        "records": 1,
+                        "ranges": [
+                          "3 <= key3 <= 3"
+                        ]
+                      }
+                    ],
+                    "total_records": 2,
+                    "total_cost": 6.327,
+                    "chosen": true
+                  },
+                  "records": 2
+                }
+              }
+            ]
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "table": "t1",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_range_access": true,
+                      "with_where_cond_processing": {
+                        "records": 2,
+                        "cost": 6.327
+                      },
+                      "chosen": true
+                    }
+                  ]
+                },
+                "cost_for_plan": 6.327,
+                "records_for_plan": 2,
+                "chosen": true
+              }
+            ]
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`test`.`t1`.`key2` = 10) or (`test`.`t1`.`key3` = 3) or (`test`.`t1`.`key4` <=> NULL))",
+              "attached_conditions": [
+                {
+                  "table": "t1",
+                  "attached": "((`test`.`t1`.`key2` = 10) or (`test`.`t1`.`key3` = 3) or (`test`.`t1`.`key4` <=> NULL))"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
+
+EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t2	ALL	i2_1,i2_2	NULL	NULL	NULL	1024	Using where
+
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+TRACE
+{
+  "top_query": "EXPLAIN SELECT * FROM t2 WHERE key2_1 < 79 OR key2 = 2",
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t2` where ((`key2_1` < 79) or (`key2` = 2))"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`test`.`t2`.`key2_1` < 79) or (`test`.`t2`.`key2` = 2))",
+              "after_equality_propagation": "((`test`.`t2`.`key2_1` < 79) or multiple equal(2, `test`.`t2`.`key2`))",
+              "after_constant_propagation": "((`test`.`t2`.`key2_1` < 79) or multiple equal(2, `test`.`t2`.`key2`))",
+              "after_trivial_conditions_removal": "((`test`.`t2`.`key2_1` < 79) or multiple equal(2, `test`.`t2`.`key2`))"
+            }
+          },
+          {
+            "ref-optimizer-key-uses": [
+            ]
+          },
+          {
+            "constant_tables": [
+            ],
+            "records_estimation": [
+              {
+                "table": "t2",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 1024,
+                    "cost": 215.15
+                  },
+                  "potential_range_indices": [
+                    {
+                      "index": "i1a",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i1b",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i2_1",
+                      "key_parts": [
+                        "key2",
+                        "key2_1"
+                      ]
+                    },
+                    {
+                      "index": "i2_2",
+                      "key_parts": [
+                        "key2",
+                        "key2_1"
+                      ]
+                    }
+                  ],
+                  "range_scan_possible": false,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  },
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  },
+                  "records": 1024
+                }
+              }
+            ]
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "table": "t2",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 1024,
+                        "cost": 8.25
+                      },
+                      "chosen": true
+                    }
+                  ]
+                },
+                "cost_for_plan": 8.25,
+                "records_for_plan": 1024,
+                "chosen": true
+              }
+            ]
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`test`.`t2`.`key2_1` < 79) or (`test`.`t2`.`key2` = 2))",
+              "attached_conditions": [
+                {
+                  "table": "t2",
+                  "attached": "((`test`.`t2`.`key2_1` < 79) or (`test`.`t2`.`key2` = 2))"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
+
+EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2  > 2);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ALL	i1,i2	NULL	NULL	NULL	1024	Using where
+
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+TRACE
+{
+  "top_query": "EXPLAIN SELECT * FROM t1 WHERE (key1 > 1 OR key2  > 2)",
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`key1` > 1) or (`key2` > 2))"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))",
+              "after_equality_propagation": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))",
+              "after_constant_propagation": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))",
+              "after_trivial_conditions_removal": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))"
+            }
+          },
+          {
+            "ref-optimizer-key-uses": [
+            ]
+          },
+          {
+            "constant_tables": [
+            ],
+            "records_estimation": [
+              {
+                "table": "t1",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 1024,
+                    "cost": 217.15
+                  },
+                  "potential_range_indices": [
+                    {
+                      "index": "i1",
+                      "key_parts": [
+                        "key1"
+                      ]
+                    },
+                    {
+                      "index": "i2",
+                      "key_parts": [
+                        "key2"
+                      ]
+                    },
+                    {
+                      "index": "i3",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i4",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i5",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i6",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i7",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    },
+                    {
+                      "index": "i8",
+                      "usable": false,
+                      "cause": "not_in_keys_to_use"
+                    }
+                  ],
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  },
+                  "analyzing_index_merge": [
+                    {
+                      "indices_to_merge": [
+                        {
+                          "range_scan_alternatives": [
+                            {
+                              "index": "i1",
+                              "ranges": [
+                                "1 < key1"
+                              ],
+                              "index_only": true,
+                              "records": 1023,
+                              "cost": 227.35,
+                              "rowid_ordered": false,
+                              "chosen": false,
+                              "cause": "higher_cost"
+                            }
+                          ],
+                          "chosen": false,
+                          "cause": "expensive"
+                        },
+                        {
+                          "range_scan_alternatives": [
+                            {
+                              "index": "i2",
+                              "ranges": [
+                                "2 < key2"
+                              ],
+                              "index_only": true,
+                              "records": 1022,
+                              "cost": 227.13,
+                              "rowid_ordered": false,
+                              "chosen": false,
+                              "cause": "higher_cost"
+                            }
+                          ],
+                          "chosen": false,
+                          "cause": "expensive"
+                        }
+                      ],
+                      "scan_cost": 0,
+                      "chosen": false,
+                      "cause": "more_expensive_than_table_scan"
+                    }
+                  ],
+                  "chosen_range_access_summary": {
+                    "chosen": false
+                  },
+                  "records": 1024
+                }
+              }
+            ]
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "table": "t1",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "scan",
+                      "using_range_access": false,
+                      "using_join_cache": true,
+                      "with_where_cond_processing": {
+                        "records": 1024,
+                        "cost": 10.25
+                      },
+                      "chosen": true
+                    }
+                  ]
+                },
+                "cost_for_plan": 10.25,
+                "records_for_plan": 1024,
+                "chosen": true
+              }
+            ]
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))",
+              "attached_conditions": [
+                {
+                  "table": "t1",
+                  "attached": "((`test`.`t1`.`key1` > 1) or (`test`.`t1`.`key2` > 2))"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
+
+DROP TABLE t1,t2;
+CREATE TABLE t1 (
+cola char(3) not null, 
+colb char(3) not null,  
+filler char(200),
+key(cola), 
+key(colb)
+) engine=innodb;
+INSERT INTO t1 VALUES ('foo','bar', 'ZZ'),('fuz','baz', 'ZZ');
+Inserting records
+
+EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	index_merge	cola,colb	cola,colb	3,3	NULL	31	Using intersect(cola,colb); Using where
+
+SELECT TRACE FROM information_schema.OPTIMIZER_TRACE;
+TRACE
+{
+  "top_query": "EXPLAIN SELECT * FROM t1 WHERE cola = 'foo' AND colb = 'bar'",
+  "steps": [
+    {
+      "expanded_query": "/* select#1 */ select `*` AS `*` from `test`.`t1` where ((`cola` = 'foo') and (`colb` = 'bar'))"
+    },
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+        ]
+      }
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`test`.`t1`.`cola` = 'foo') and (`test`.`t1`.`colb` = 'bar'))",
+              "after_equality_propagation": "(multiple equal('foo', `test`.`t1`.`cola`) and multiple equal('bar', `test`.`t1`.`colb`))",
+              "after_constant_propagation": "(multiple equal('foo', `test`.`t1`.`cola`) and multiple equal('bar', `test`.`t1`.`colb`))",
+              "after_trivial_conditions_removal": "(multiple equal('foo', `test`.`t1`.`cola`) and multiple equal('bar', `test`.`t1`.`colb`))"
+            }
+          },
+          {
+            "ref-optimizer-key-uses": [
+              {
+                "condition": "t1.cola= 'foo'",
+                "null_rejecting": false
+              },
+              {
+                "condition": "t1.colb= 'bar'",
+                "null_rejecting": false
+              }
+            ]
+          },
+          {
+            "constant_tables": [
+            ],
+            "records_estimation": [
+              {
+                "table": "t1",
+                "range_analysis": {
+                  "table_scan": {
+                    "records": 8225,
+                    "cost": 1808.1
+                  },
+                  "potential_range_indices": [
+                    {
+                      "index": "cola",
+                      "key_parts": [
+                        "cola"
+                      ]
+                    },
+                    {
+                      "index": "colb",
+                      "key_parts": [
+                        "colb"
+                      ]
+                    }
+                  ],
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  },
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "cola",
+                        "ranges": [
+                          "foo <= cola <= foo"
+                        ],
+                        "index_only": false,
+                        "records": 512,
+                        "cost": 615.41,
+                        "rowid_ordered": true,
+                        "chosen": true
+                      },
+                      {
+                        "index": "colb",
+                        "ranges": [
+                          "bar <= colb <= bar"
+                        ],
+                        "index_only": false,
+                        "records": 512,
+                        "cost": 615.41,
+                        "rowid_ordered": true,
+                        "chosen": false,
+                        "cause": "higher_cost"
+                      }
+                    ],
+                    "analyzing_ror_intersect": {
+                      "intersecting_indices": [
+                        {
+                          "index": "cola",
+                          "used_in_intersect": true,
+                          "matching_records_now": 512,
+                          "cost_now": 518.14,
+                          "covering_now": false
+                        },
+                        {
+                          "index": "colb",
+                          "used_in_intersect": true,
+                          "matching_records_now": 31.872,
+                          "cost_now": 34.399,
+                          "covering_now": false
+                        }
+                      ],
+                      "clustered_pk": {
+                        "cpk_added_to_intersect": false,
+                        "cause": "no_clustered_pk_index"
+                      },
+                      "records": 31,
+                      "cost": 34.399,
+                      "is_covering": false,
+                      "cpk_scan": false,
+                      "chosen": true
+                    }
+                  },
+                  "chosen_range_access_summary": {
+                    "table_read_plan_type": "index_roworder_intersect",
+                    "records": 31,
+                    "cost": 34.399,
+                    "is_covering": false,
+                    "cpk_scan": false,
+                    "intersect_of": [
+                      {
+                        "table_read_plan_type": "range_scan",
+                        "index": "cola",
+                        "records": 512,
+                        "ranges": [
+                          "foo <= cola <= foo"
+                        ]
+                      },
+                      {
+                        "table_read_plan_type": "range_scan",
+                        "index": "colb",
+                        "records": 512,
+                        "ranges": [
+                          "bar <= colb <= bar"
+                        ]
+                      }
+                    ],
+                    "total_records": 31,
+                    "total_cost": 34.399,
+                    "chosen": true
+                  },
+                  "records": 31
+                }
+              }
+            ]
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "table": "t1",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "index",
+                      "index": "cola",
+                      "records": 512,
+                      "cost": 483,
+                      "chosen": true
+                    },
+                    {
+                      "access_type": "index",
+                      "index": "colb",
+                      "records": 512,
+                      "cost": 483,
+                      "chosen": false
+                    },
+                    {
+                      "access_type": "scan",
+                      "using_range_access": true,
+                      "with_where_cond_processing": {
+                        "records": 24,
+                        "cost": 35.799
+                      },
+                      "chosen": true
+                    }
+                  ]
+                },
+                "cost_for_plan": 35.799,
+                "records_for_plan": 24,
+                "chosen": true
+              }
+            ]
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`test`.`t1`.`colb` = 'bar') and (`test`.`t1`.`cola` = 'foo'))",
+              "attached_conditions": [
+                {
+                  "table": "t1",
+                  "attached": "((`test`.`t1`.`colb` = 'bar') and (`test`.`t1`.`cola` = 'foo'))"
+                }
+              ]
+            }
+          }
+        ]
+      }
+    }
+  ]
+}
+DROP TABLE t1;
+set optimizer_trace=default;

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2010-09-27 09:26:39 +0000
+++ b/sql/handler.cc	2010-10-07 09:02:31 +0000
@@ -4381,14 +4381,12 @@ handler::multi_range_read_info_const(uin
   *bufsz= 0;
 
   seq_it= seq->init(seq_init_param, n_ranges, *flags);
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
   /*
     Given that this method can be overridden by engines, it doesn't sound
     smart to do tracing here. seq->next() produces tracing when it's equal to
     sel_arg_range_seq_next() (prints the range).
   */
   Opt_trace_array ota(thd->opt_trace, "ranges");
-#endif
   while (!seq->next(seq_it, &range))
   {
     if (unlikely(thd->killed != 0))

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2010-09-27 09:26:39 +0000
+++ b/sql/opt_range.cc	2010-10-07 09:02:31 +0000
@@ -30,7 +30,8 @@
     and builds lists of intervals (in index/partitioning space), such that 
     all possible records that match the condition are contained within the 
     intervals.
-    The entry point for the range analysis module is get_mm_tree() function.
+    The entry point for the range analysis module is get_mm_tree() 
+    (mm=min_max) function.
     
     The lists are returned in form of complicated structure of interlinked
     SEL_TREE/SEL_IMERGE/SEL_ARG objects.
@@ -756,7 +757,7 @@ class TABLE_READ_PLAN;
   class TRP_RANGE;
   class TRP_ROR_INTERSECT;
   class TRP_ROR_UNION;
-  class TRP_ROR_INDEX_MERGE;
+  class TRP_INDEX_MERGE;
   class TRP_GROUP_MIN_MAX;
 
 struct st_ror_scan_info;
@@ -803,13 +804,12 @@ static void print_ror_scans_arr(TABLE *t
                                 struct st_ror_scan_info **end);
 #endif
 #if !defined(DBUG_OFF) || defined(OPTIMIZER_TRACE)
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
 static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg);
-#endif
-static void print_range(Opt_trace_context *out, KEY_PART_INFO *key_parts, 
-                        const uchar *min_key, uint16 min_length,
-                        const uchar *max_key, uint16 max_length, 
-                        uint flag);
+static void append_range(String *out,
+                         KEY_PART_INFO *key_parts, 
+                         const uchar *min_key, uint16 min_length,
+                         const uchar *max_key, uint16 max_length, 
+                         uint flag);
 #endif
 
 static SEL_TREE *tree_and(RANGE_OPT_PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
@@ -1955,13 +1955,69 @@ public:
   static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); }
   static void operator delete(void *ptr, MEM_ROOT *mem_root) { /* Never called */ }
   virtual ~TABLE_READ_PLAN() {}               /* Remove gcc warning */
+  /**
+     Return the name of the TABLE_READ_PLAN ("range_scan", "index_merge" etc)
+
+     @return The name of the plan, zero terminated 
+   */
+  virtual const char *get_name() const = 0;
+  /**
+     Add basic info for this TABLE_READ_PLAN to the optimizer trace.
 
+     @param param Parameters for range analysis of this table
+     @param trace The optimizer trace object the info is appended to
+   */
+  virtual void trace_basic_info(const PARAM *param, 
+                                Opt_trace_object *trace) const = 0;
+  
 };
 
-class TRP_ROR_INTERSECT;
-class TRP_ROR_UNION;
-class TRP_INDEX_MERGE;
+/**
+  Print a key into a stream
 
+  @param[out] out          String the key is appended to
+  @param[in]  key_part     Index components description
+  @param[in]  key          Key tuple
+  @param[in]  used_length  Key tuple length
+*/
+static void
+print_key2(String *out, KEY_PART_INFO *key_part, const uchar *key, 
+           uint used_length)
+{
+  const uchar *key_end= key+used_length;
+  String tmp;
+  uint store_length;
+  TABLE *table= key_part->field->table;
+  my_bitmap_map *old_sets[2];
+
+  dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
+
+  for (; key < key_end; key+=store_length, key_part++)
+  {
+    Field *field=      key_part->field;
+    store_length= key_part->store_length;
+
+    if (field->real_maybe_null())
+    {
+      if (*key)
+      {
+        out->append("NULL", 4);
+        continue;
+      }
+      key++;                                    // Skip null byte
+      store_length--;
+    }
+    field->set_key_image(key, key_part->length);
+    if (field->type() == MYSQL_TYPE_BIT)
+      (void) field->val_int_as_str(&tmp, 1);
+    else
+      field->val_str(&tmp);
+    out->append(tmp.ptr(), tmp.length());
+    if (key+store_length < key_end)
+      out->append("'",1);
+  }
+  dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
+}
 
 /*
   Plan for a QUICK_RANGE_SELECT scan.
@@ -1996,8 +2052,54 @@ public:
     }
     DBUG_RETURN(quick);
   }
+  const char *get_name() const {return "range_scan";}
+  void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+  {
+    trace->add("table_read_plan_type", get_name()).
+      add("index", param->table->key_info[param->real_keynr[key_idx]].name).
+      add("records", records);
+
+    Opt_trace_array trace_range(param->thd->opt_trace,"ranges");
+    KEY_PART_INFO *key_part= 
+      param->table->key_info[param->real_keynr[key_idx]].key_part;
+    for (SEL_ARG *current= key; current; current= current->next)
+    {
+      String multikey;
+      for (SEL_ARG *part= current; part; part= part->next_key_part)
+      {
+        int length= (key_part+part->part)->length;
+        append_range(&multikey, key_part+part->part,
+                     part->min_value, length,
+                     part->max_value, length,
+                     part->min_flag|part->max_flag);
+      }
+      trace_range.add(multikey.c_ptr());
+    }
+  }
 };
 
+typedef struct st_ror_scan_info
+{
+  uint      idx;      ///< # of used key in param->keys
+  uint      keynr;    ///< # of used key in table
+  ha_rows   records;  ///< estimate of # records this scan will return
+
+  /** Set of intervals over key fields that will be used for row retrieval. */
+  SEL_ARG   *sel_arg;
+
+  /** Fields used in the query and covered by this ROR scan. */
+  MY_BITMAP covered_fields;
+  uint      used_fields_covered; ///< # of set bits in covered_fields
+  int       key_rec_length; ///< length of key record (including rowid)
+
+  /**
+    Cost of reading all index records with values in sel_arg intervals set
+    (assuming there is no need to access full table records)
+  */
+  double    index_read_cost;
+  uint      first_uncovered_field; ///< first unused bit in covered_fields
+  uint      key_components; ///< # of parts in the key
+} ROR_SCAN_INFO;
 
 /* Plan for QUICK_ROR_INTERSECT_SELECT scan. */
 
@@ -2015,6 +2117,48 @@ public:
   struct st_ror_scan_info *cpk_scan;  /* Clustered PK scan, if there is one */
   bool is_covering; /* TRUE if no row retrieval phase is necessary */
   double index_scan_costs; /* SUM(cost(index_scan)) */
+  const char *get_name() const {return "index_roworder_intersect";}
+  void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+  {
+    trace->add("table_read_plan_type", get_name()).
+      add("records", records).
+      add("cost", read_cost).
+      add("is_covering", is_covering).
+      add("cpk_scan", cpk_scan ? true : false);
+      
+    Opt_trace_array ota(param->thd->opt_trace,"intersect_of");
+    for (st_ror_scan_info **cur_scan= first_scan; 
+         cur_scan != last_scan; 
+         cur_scan++)
+    {
+      KEY key= param->table->key_info[param->real_keynr[(*cur_scan)->keynr]];
+      
+      Opt_trace_object trace_isect_idx(param->thd->opt_trace);
+      trace_isect_idx.add("table_read_plan_type", "range_scan").
+        add("index", key.name).
+        add("records", (*cur_scan)->records);
+      {
+        Opt_trace_array trace_range(param->thd->opt_trace,"ranges");
+        for (SEL_ARG *current= (*cur_scan)->sel_arg; 
+             current; 
+             current= current->next)
+        {
+          String range;
+          for (SEL_ARG *part= current; 
+               part; 
+               part= part->next_key_part)
+          {
+            KEY_PART_INFO *key_part= key.key_part+part->part;
+            append_range(&range, key_part,
+                         part->min_value, key_part->length,
+                         part->max_value, key_part->length,
+                         part->min_flag|part->max_flag);
+          }
+          trace_range.add(range.c_ptr());
+        }
+      }
+    }
+  }
 };
 
 
@@ -2033,6 +2177,19 @@ public:
                              MEM_ROOT *parent_alloc);
   TABLE_READ_PLAN **first_ror; /* array of ptrs to plans for merged scans */
   TABLE_READ_PLAN **last_ror;  /* end of the above array */
+  const char *get_name() const {return "index_roworder_union";}
+  void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+  {
+    trace->add("table_read_plan_type", get_name());
+    Opt_trace_array ota(param->thd->opt_trace, "union_of");
+    for (TABLE_READ_PLAN **current= first_ror; 
+         current != last_ror;
+         current++)
+    {
+      Opt_trace_object trp_info(param->thd->opt_trace);
+      (*current)->trace_basic_info(param,&trp_info);
+    }
+  }
 };
 
 
@@ -2051,6 +2208,19 @@ public:
                              MEM_ROOT *parent_alloc);
   TRP_RANGE **range_scans; /* array of ptrs to plans of merged scans */
   TRP_RANGE **range_scans_end; /* end of the array */
+  const char *get_name() const {return "index_merge";}
+  void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+  {
+    trace->add("table_read_plan_type", get_name());
+    Opt_trace_array ota(param->thd->opt_trace, "index_merge_of");
+    for (TRP_RANGE **current= range_scans; 
+         current != range_scans_end;
+         current++)
+    {
+      Opt_trace_object trp_info(param->thd->opt_trace);
+      (*current)->trace_basic_info(param,&trp_info);
+    }
+  }
 };
 
 
@@ -2078,6 +2248,15 @@ public:
   /* Number of records selected by the ranges in index_tree. */
   ha_rows quick_prefix_records;
 public:
+  const char *get_idx_name() const {return index_info->name;}
+  const char *get_name() const {return "index_group";}
+  void trace_basic_info(const PARAM *param, Opt_trace_object *trace) const
+  {
+    trace->add("table_read_plan_type", get_name()).
+      add("index", get_idx_name()).
+      add("records", records).
+      add("cost", read_cost);
+  }
   TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg, 
                     bool have_agg_distinct_arg,
                     KEY_PART_INFO *min_max_arg_part_arg,
@@ -2246,12 +2425,10 @@ int SQL_SELECT::test_quick_select(THD *t
   else if (read_time <= 2.0 && !force_quick_range)
     DBUG_RETURN(0);				/* No need for quick select */
 
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-  Opt_trace_object oto(thd->opt_trace, "range_analysis");
+  Opt_trace_object trace_range(thd->opt_trace, "range_analysis");
   Opt_trace_object(thd->opt_trace, "table_scan").
-    add(head->file->stats.records, "records").
-    add(read_time, "cost");
-#endif
+    add("records", head->file->stats.records).
+    add("cost", read_time);
 
   keys_to_use.intersect(head->keys_in_use_for_query);
   if (!keys_to_use.is_clear_all())
@@ -2302,9 +2479,7 @@ int SQL_SELECT::test_quick_select(THD *t
     thd->mem_root= &alloc;
 
     {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-      Opt_trace_object oto1(thd->opt_trace, "indices");
-#endif
+      Opt_trace_array trace_idx(thd->opt_trace, "potential_range_indices");
       /*
         Make an array with description of all key parts of all table keys.
         This is used in get_mm_parts function.
@@ -2312,17 +2487,25 @@ int SQL_SELECT::test_quick_select(THD *t
       key_info= head->key_info;
       for (idx=0 ; idx < head->s->keys ; idx++, key_info++)
       {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-        oto1.add(key_info->name, "index");
-#endif
+        Opt_trace_object trace_idx_details(thd->opt_trace);
+        trace_idx_details.add("index", key_info->name);
         KEY_PART_INFO *key_part_info;
         if (!keys_to_use.is_set(idx))
+        {
+          trace_idx_details.add("usable", false).
+            add("cause", "not_in_keys_to_use");
           continue;
+        }
         if (key_info->flags & HA_FULLTEXT)
+        {
+          trace_idx_details.add("usable", false).
+            add("cause", "fulltext");
           continue;    // ToDo: ft-keys in non-ft ranges, if possible   SerG
+        }
 
         param.key[param.keys]=key_parts;
         key_part_info= key_info->key_part;
+        Opt_trace_array trace_keypart(thd->opt_trace, "key_parts");
         for (uint part=0 ; part < key_info->key_parts ;
              part++, key_parts++, key_part_info++)
         {
@@ -2336,6 +2519,7 @@ int SQL_SELECT::test_quick_select(THD *t
             (key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
           /* Only HA_PART_KEY_SEG is used */
           key_parts->flag=         (uint8) key_part_info->key_part_flag;
+          trace_keypart.add(key_parts->field->field_name);
         }
         param.real_keynr[param.keys++]=idx;
       }
@@ -2359,12 +2543,10 @@ int SQL_SELECT::test_quick_select(THD *t
         chosen= true;
       }
 
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-      Opt_trace_object(thd->opt_trace, "best_covering_scan").
-        add(head->key_info[key_for_use].name, "index").
-        add(key_read_time, "cost").
-        add(chosen, "chosen");
-#endif
+      Opt_trace_object(thd->opt_trace, "best_full_index_scan").
+        add("index", head->key_info[key_for_use].name).
+        add("cost", key_read_time).
+        add("chosen", chosen);
     }
 
     TABLE_READ_PLAN *best_trp= NULL;
@@ -2377,6 +2559,8 @@ int SQL_SELECT::test_quick_select(THD *t
       {
         if (tree->type == SEL_TREE::IMPOSSIBLE)
         {
+          trace_range.add("impossible_select", true).
+            add("stop_range_analysis", true);
           records=0L;                      /* Return -1 from this function. */
           read_time= (double) HA_POS_ERROR;
           goto free_mem;
@@ -2386,7 +2570,10 @@ int SQL_SELECT::test_quick_select(THD *t
           can construct a group-min-max quick select
         */
         if (tree->type != SEL_TREE::KEY && tree->type != SEL_TREE::KEY_SMALLER)
+        {
+          trace_range.add("range_scan_possible", false);
           tree= NULL;
+        }
       }
     }
 
@@ -2399,6 +2586,9 @@ int SQL_SELECT::test_quick_select(THD *t
     {
       param.table->quick_condition_rows= min(group_trp->records,
                                              head->file->stats.records);
+      Opt_trace_object grp_summary(thd->opt_trace, "best_group_range_summary");
+      group_trp->trace_basic_info(&param, &grp_summary);
+
       if (group_trp->read_cost < best_read_time)
       {
         best_trp= group_trp;
@@ -2414,6 +2604,8 @@ int SQL_SELECT::test_quick_select(THD *t
       */
       if (tree->merges.is_empty())
       {
+        Opt_trace_object trace_range(thd->opt_trace, 
+                                     "analyzing_range_alternatives");
         TRP_RANGE         *range_trp;
         TRP_ROR_INTERSECT *rori_trp;
         bool can_build_covering= FALSE;
@@ -2450,7 +2642,10 @@ int SQL_SELECT::test_quick_select(THD *t
             if (!rori_trp->is_covering && can_build_covering &&
                 (rori_trp= get_best_covering_ror_intersect(&param, tree,
                                                            best_read_time)))
+            {
+              trace_range.add("made_ror_intersect_covering", true);
               best_trp= rori_trp;
+            }
           }
         }
       }
@@ -2465,18 +2660,26 @@ int SQL_SELECT::test_quick_select(THD *t
           DBUG_PRINT("info",("No range reads possible,"
                              " trying to construct index_merge"));
           List_iterator_fast<SEL_IMERGE> it(tree->merges);
-          while ((imerge= it++))
           {
-            new_conj_trp= get_best_disjunct_quick(&param, imerge, best_read_time);
-            if (new_conj_trp)
-              set_if_smaller(param.table->quick_condition_rows, 
-                             new_conj_trp->records);
-            if (!best_conj_trp || (new_conj_trp && new_conj_trp->read_cost <
-                                   best_conj_trp->read_cost))
-              best_conj_trp= new_conj_trp;
+            Opt_trace_array trace_idx_merge(thd->opt_trace, 
+                                            "analyzing_index_merge");
+            while ((imerge= it++))
+            {
+              new_conj_trp= get_best_disjunct_quick(&param, imerge, 
+                                                    best_read_time);
+              if (new_conj_trp)
+                set_if_smaller(param.table->quick_condition_rows, 
+                               new_conj_trp->records);
+              if (!best_conj_trp || 
+                  (new_conj_trp && 
+                   new_conj_trp->read_cost < best_conj_trp->read_cost))
+              {
+                best_conj_trp= new_conj_trp;
+              }
+            }
+            if (best_conj_trp)
+              best_trp= best_conj_trp;
           }
-          if (best_conj_trp)
-            best_trp= best_conj_trp;
         }
       }
     }
@@ -2492,20 +2695,68 @@ int SQL_SELECT::test_quick_select(THD *t
         delete quick;
         quick= NULL;
       }
+      else
+      {
+      }
+    }
+
+free_mem:
+    Opt_trace_object trace_range_summary(thd->opt_trace, 
+                                         "chosen_range_access_summary");
+    if (quick)
+    {
+      /* Guilhem question: I've worked with two alternative ways of
+         printing the chosen range access.
+
+         1) Use trace_basic_info() of the TABLE_READ_PLAN object. This
+            can print multi-key-part ranges separately (I prefer this)
+
+         2) Use dbug_dump() of the QUICK_SELECT object. Maybe
+            conceptually more correct since it is what will be
+            executed, but I cannot make it print multi-key-part ranges
+            in an understandable way (and I tried a lot). This is
+            Sergey's way of doing it.
+
+            Consider 
+            SELECT * FROM t2 WHERE key1a = 3 and key1b < 10 and key2=0
+
+            1) will print
+                  "ranges": [
+                    {
+                      "3 <= field1 <= 3" : "field2 < 10"
+                      ]
+                    }
+                  ],
+ 
+            2) will print
+                 "ranges": [
+                   "3 <= X < 3'10"            <- must print X, not field name
+                 ]
+      */
+      // 1
+      best_trp->trace_basic_info(&param, &trace_range_summary);
+
+      // 2 (note: currently prints field name of first field in index,
+      //   but that will be changed if we go for this option)
+      /* 
+        print_quick(quick, &needed_reg);    
+      */
+
+      trace_range_summary.add("total_records", quick->records).
+        add("total_cost", quick->read_time).
+        add("chosen", true);
+    }
+    else
+    {
+      trace_range_summary.add("chosen", false);
+      print_quick(quick, &needed_reg);
     }
 
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-    oto.add(param.table->quick_condition_rows, "quick_condition_rows");
-#endif
-  free_mem:
     free_root(&alloc,MYF(0));			// Return memory & allocator
     thd->mem_root= param.old_root;
     thd->no_errors=0;
   }
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-  oto.add(records, "records");
-  OPT_TRACE2(thd->opt_trace, print_quick(quick, &needed_reg));
-#endif
+  trace_range.add("records", records);
 
   /*
     Assume that if the user is using 'limit' we will only need to scan
@@ -3837,48 +4088,59 @@ TABLE_READ_PLAN *get_best_disjunct_quick
   DBUG_ENTER("get_best_disjunct_quick");
   DBUG_PRINT("info", ("Full table scan cost: %g", read_time));
 
+  Opt_trace_object trace_best_disjunct(param->thd->opt_trace);
   if (!(range_scans= (TRP_RANGE**)alloc_root(param->mem_root,
                                              sizeof(TRP_RANGE*)*
                                              n_child_scans)))
     DBUG_RETURN(NULL);
-  /*
-    Collect best 'range' scan for each of disjuncts, and, while doing so,
-    analyze possibility of ROR scans. Also calculate some values needed by
-    other parts of the code.
-  */
-  for (ptree= imerge->trees, cur_child= range_scans;
-       ptree != imerge->trees_next;
-       ptree++, cur_child++)
-  {
-    DBUG_EXECUTE("info", print_sel_tree(param, *ptree, &(*ptree)->keys_map,
-                                        "tree in SEL_IMERGE"););
-    if (!(*cur_child= get_key_scans_params(param, *ptree, TRUE, FALSE, read_time)))
-    {
-      /*
-        One of index scans in this index_merge is more expensive than entire
-        table read for another available option. The entire index_merge (and
-        any possible ROR-union) will be more expensive then, too. We continue
-        here only to update SQL_SELECT members.
-      */
-      imerge_too_expensive= TRUE;
-    }
-    if (imerge_too_expensive)
-      continue;
+  {
+    /*
+      Collect best 'range' scan for each of disjuncts, and, while doing so,
+      analyze possibility of ROR scans. Also calculate some values needed by
+      other parts of the code.
+    */
+    Opt_trace_array ota(param->thd->opt_trace,"indices_to_merge");
+    for (ptree= imerge->trees, cur_child= range_scans;
+         ptree != imerge->trees_next;
+         ptree++, cur_child++)
+    {
+      DBUG_EXECUTE("info", print_sel_tree(param, *ptree, &(*ptree)->keys_map,
+                                          "tree in SEL_IMERGE"););
+      Opt_trace_object trace_idx(param->thd->opt_trace);
+      if (!(*cur_child= 
+            get_key_scans_params(param, *ptree, TRUE, FALSE, read_time)))
+      {
+        /*
+          One of index scans in this index_merge is more expensive than entire
+          table read for another available option. The entire index_merge (and
+          any possible ROR-union) will be more expensive then, too. We continue
+          here only to update SQL_SELECT members.
+        */
+        trace_idx.add("chosen", false).add("cause", "expensive");
+        imerge_too_expensive= TRUE;
+      }
+      if (imerge_too_expensive)
+        continue;
 
-    imerge_cost += (*cur_child)->read_cost;
-    all_scans_ror_able &= ((*ptree)->n_ror_scans > 0);
-    all_scans_rors &= (*cur_child)->is_ror;
-    if (pk_is_clustered &&
-        param->real_keynr[(*cur_child)->key_idx] ==
-        param->table->s->primary_key)
-    {
-      cpk_scan= cur_child;
-      cpk_scan_records= (*cur_child)->records;
+      uint real_key= param->real_keynr[(*cur_child)->key_idx];
+      imerge_cost += (*cur_child)->read_cost;
+      all_scans_ror_able &= ((*ptree)->n_ror_scans > 0);
+      all_scans_rors &= (*cur_child)->is_ror;
+      if (pk_is_clustered &&
+          real_key == param->table->s->primary_key)
+      {
+        cpk_scan= cur_child;
+        cpk_scan_records= (*cur_child)->records;
+      }
+      else
+        non_cpk_scan_records += (*cur_child)->records;
+
+      trace_idx.
+        add("index_to_merge", param->table->key_info[real_key].name).
+        add("new_cost", imerge_cost);
     }
-    else
-      non_cpk_scan_records += (*cur_child)->records;
   }
-
+  trace_best_disjunct.add("scan_cost", imerge_cost);
   DBUG_PRINT("info", ("index_merge scans cost %g", imerge_cost));
   if (imerge_too_expensive || (imerge_cost > read_time) ||
       ((non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) &&
@@ -3890,6 +4152,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick
     */
     DBUG_PRINT("info", ("Sum of index_merge scans is more expensive than "
                         "full table scan, bailing out"));
+    trace_best_disjunct.add("chosen", false).
+      add("cause", "more_expensive_than_table_scan");
     DBUG_RETURN(NULL);
   }
 
@@ -3902,6 +4166,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick
       param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_UNION))
   {
     roru_read_plans= (TABLE_READ_PLAN**)range_scans;
+    trace_best_disjunct.add("use_ror_union", true).
+      add("cause", "always_cheaper_than_non_ror");
     goto skip_to_ror_scan;
   }
 
@@ -3928,6 +4194,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick
   if (imerge_cost > read_time || 
       !param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION))
   {
+    trace_best_disjunct.add("use_ror_index_merge", true).
+      add("cause", "index_merge_cheaper");
     goto build_ror_index_merge;
   }
 
@@ -3948,6 +4216,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
     Unique::get_use_cost(param->imerge_cost_buff, (uint)non_cpk_scan_records,
                          param->table->file->ref_length,
                          param->thd->variables.sortbuff_size);
+  trace_best_disjunct.add("total_cost", imerge_cost);
   DBUG_PRINT("info",("index_merge total cost: %g (wanted: less then %g)",
                      imerge_cost, read_time));
   if (imerge_cost < read_time)
@@ -3983,44 +4252,52 @@ skip_to_ror_scan:
   cur_roru_plan= roru_read_plans;
 
   /* Find 'best' ROR scan for each of trees in disjunction */
-  for (ptree= imerge->trees, cur_child= range_scans;
-       ptree != imerge->trees_next;
-       ptree++, cur_child++, cur_roru_plan++)
+  
   {
-    /*
-      Assume the best ROR scan is the one that has cheapest full-row-retrieval
-      scan cost.
-      Also accumulate index_only scan costs as we'll need them to calculate
-      overall index_intersection cost.
-    */
-    double cost;
-    if ((*cur_child)->is_ror)
+    Opt_trace_array ota(param->thd->opt_trace, "analyzing_ror_scans");
+    for (ptree= imerge->trees, cur_child= range_scans;
+         ptree != imerge->trees_next;
+         ptree++, cur_child++, cur_roru_plan++)
     {
-      /* Ok, we have index_only cost, now get full rows scan cost */
-      cost= param->table->file->
-              read_time(param->real_keynr[(*cur_child)->key_idx], 1,
-                        (*cur_child)->records) +
-              rows2double((*cur_child)->records) / TIME_FOR_COMPARE;
-    }
-    else
-      cost= read_time;
 
-    TABLE_READ_PLAN *prev_plan= *cur_child;
-    if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost,
-                                                 &dummy)))
-    {
-      if (prev_plan->is_ror)
-        *cur_roru_plan= prev_plan;
+      Opt_trace_object trp_info(param->thd->opt_trace);
+      (*cur_child)->trace_basic_info(param, &trp_info);
+
+      /*
+        Assume the best ROR scan is the one that has cheapest
+        full-row-retrieval scan cost. 
+        Also accumulate index_only scan costs as we'll need them to
+        calculate overall index_intersection cost.
+      */
+      double cost;
+      if ((*cur_child)->is_ror)
+      {
+        /* Ok, we have index_only cost, now get full rows scan cost */
+        cost= param->table->file->
+          read_time(param->real_keynr[(*cur_child)->key_idx], 1,
+                    (*cur_child)->records) +
+          rows2double((*cur_child)->records) / TIME_FOR_COMPARE;
+      }
       else
-        DBUG_RETURN(imerge_trp);
-      roru_index_costs += (*cur_roru_plan)->read_cost;
+        cost= read_time;
+
+      TABLE_READ_PLAN *prev_plan= *cur_child;
+      if (!(*cur_roru_plan= get_best_ror_intersect(param, *ptree, cost,
+                                                   &dummy)))
+      {
+        if (prev_plan->is_ror)
+          *cur_roru_plan= prev_plan;
+        else
+          DBUG_RETURN(imerge_trp);
+        roru_index_costs += (*cur_roru_plan)->read_cost;
+      }
+      else
+        roru_index_costs +=
+          ((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs;
+      roru_total_records += (*cur_roru_plan)->records;
+      roru_intersect_part *= (*cur_roru_plan)->records /
+        param->table->file->stats.records;
     }
-    else
-      roru_index_costs +=
-        ((TRP_ROR_INTERSECT*)(*cur_roru_plan))->index_scan_costs;
-    roru_total_records += (*cur_roru_plan)->records;
-    roru_intersect_part *= (*cur_roru_plan)->records /
-                           param->table->file->stats.records;
   }
 
   /*
@@ -4052,13 +4329,14 @@ skip_to_ror_scan:
                      sweep_cost.total_cost();
   }
 
-  DBUG_PRINT("info", ("ROR-union: cost %g, %d members", roru_total_cost,
-                      n_child_scans));
+  trace_best_disjunct.add("index_roworder_union_cost", roru_total_cost).
+    add("members", n_child_scans);
   TRP_ROR_UNION* roru;
   if (roru_total_cost < read_time)
   {
     if ((roru= new (param->mem_root) TRP_ROR_UNION))
     {
+      trace_best_disjunct.add("chosen", true);
       roru->first_ror= roru_read_plans;
       roru->last_ror= roru_read_plans + n_child_scans;
       roru->read_cost= roru_total_cost;
@@ -4066,34 +4344,12 @@ skip_to_ror_scan:
       DBUG_RETURN(roru);
     }
   }
+  trace_best_disjunct.add("chosen", false);
+
   DBUG_RETURN(imerge_trp);
 }
 
 
-typedef struct st_ror_scan_info
-{
-  uint      idx;      /* # of used key in param->keys */
-  uint      keynr;    /* # of used key in table */
-  ha_rows   records;  /* estimate of # records this scan will return */
-
-  /* Set of intervals over key fields that will be used for row retrieval. */
-  SEL_ARG   *sel_arg;
-
-  /* Fields used in the query and covered by this ROR scan. */
-  MY_BITMAP covered_fields;
-  uint      used_fields_covered; /* # of set bits in covered_fields */
-  int       key_rec_length; /* length of key record (including rowid) */
-
-  /*
-    Cost of reading all index records with values in sel_arg intervals set
-    (assuming there is no need to access full table records)
-  */
-  double    index_read_cost;
-  uint      first_uncovered_field; /* first unused bit in covered_fields */
-  uint      key_components; /* # of parts in the key */
-} ROR_SCAN_INFO;
-
-
 /*
   Create ROR_SCAN_INFO* structure with a single ROR scan on index idx using
   sel_arg set of intervals.
@@ -4614,9 +4870,17 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
   double min_cost= DBL_MAX;
   DBUG_ENTER("get_best_ror_intersect");
 
+  Opt_trace_object trace_ror(param->thd->opt_trace, "analyzing_ror_intersect");
+
   if ((tree->n_ror_scans < 2) || !param->table->file->stats.records ||
       !param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT))
+  {
+    if (tree->n_ror_scans < 2)
+      trace_ror.add("usable", false).add("cause", "too_few_ror_scans");
+    else
+      trace_ror.add("usable", false).add("done_tracing", false);
     DBUG_RETURN(NULL);
+  }
 
   /*
     Step1: Collect ROR-able SEL_ARGs and create ROR_SCAN_INFO for each of 
@@ -4683,28 +4947,42 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
   ROR_SCAN_INFO **intersect_scans_best;
   cur_ror_scan= tree->ror_scans;
   intersect_scans_best= intersect_scans;
-  while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering)
   {
-    /* S= S + first(R);  R= R - first(R); */
-    if (!ror_intersect_add(intersect, *cur_ror_scan, FALSE))
+    Opt_trace_array ota(param->thd->opt_trace, "intersecting_indices");
+    while (cur_ror_scan != tree->ror_scans_end && !intersect->is_covering)
     {
-      cur_ror_scan++;
-      continue;
-    }
+      Opt_trace_object trace_idx(param->thd->opt_trace);
+      trace_idx.add("index", 
+                    param->table->key_info[(*cur_ror_scan)->keynr].name);
+      /* S= S + first(R);  R= R - first(R); */
+      if (!ror_intersect_add(intersect, *cur_ror_scan, FALSE))
+      {
+        trace_idx.add("used_in_intersect", false).
+          add("cause", "cost_not_reduced");
+        cur_ror_scan++;
+        continue;
+      }
     
-    *(intersect_scans_end++)= *(cur_ror_scan++);
-
-    if (intersect->total_cost < min_cost)
-    {
-      /* Local minimum found, save it */
-      ror_intersect_cpy(intersect_best, intersect);
-      intersect_scans_best= intersect_scans_end;
-      min_cost = intersect->total_cost;
+      trace_idx.add("used_in_intersect", true).
+        add("matching_records_now", intersect->out_rows).
+        add("cost_now", intersect->total_cost).
+        add("covering_now", intersect->is_covering);
+
+      *(intersect_scans_end++)= *(cur_ror_scan++);
+
+      if (intersect->total_cost < min_cost)
+      {
+        /* Local minimum found, save it */
+        ror_intersect_cpy(intersect_best, intersect);
+        intersect_scans_best= intersect_scans_end;
+        min_cost = intersect->total_cost;
+      }
     }
   }
 
   if (intersect_scans_best == intersect_scans)
   {
+    trace_ror.add("increases_selectivity", false).add("chosen", false);
     DBUG_PRINT("info", ("None of scans increase selectivity"));
     DBUG_RETURN(NULL);
   }
@@ -4728,9 +5006,22 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
     if (ror_intersect_add(intersect, cpk_scan, TRUE) && 
         (intersect->total_cost < min_cost))
     {
+      Opt_trace_object (param->thd->opt_trace, "clustered_pk").
+        add("cpk_scan_added_to_intersect", true).
+        add("new_cost", intersect->total_cost);
       cpk_scan_used= TRUE;
       intersect_best= intersect; //just set pointer here
     }
+    else
+      Opt_trace_object (param->thd->opt_trace, "clustered_pk").
+        add("cpk_added_to_intersect", false).add("cause", "increased_cost");
+  } 
+  else 
+  {
+    Opt_trace_object trace_cpk(param->thd->opt_trace, "clustered_pk");
+    trace_cpk.add("cpk_added_to_intersect", false);
+    cpk_scan ? trace_cpk.add("cause", "ror_is_covering")
+             : trace_cpk.add("cause", "no_clustered_pk_index");
   }
 
   /* Ok, return ROR-intersect plan if we have found one */
@@ -4755,10 +5046,19 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
     trp->records= best_rows;
     trp->index_scan_costs= intersect_best->index_scan_costs;
     trp->cpk_scan= cpk_scan_used? cpk_scan: NULL;
+
+    trace_ror.add("records", trp->records).
+      add("cost", trp->read_cost).
+      add("is_covering", trp->is_covering).
+      add("cpk_scan", cpk_scan_used).
+      add("chosen", true);
+
     DBUG_PRINT("info", ("Returning non-covering ROR-intersect plan:"
                         "cost %g, records %lu",
                         trp->read_cost, (ulong) trp->records));
   }
+  else 
+    trace_ror.add("chosen", false);
   DBUG_RETURN(trp);
 }
 
@@ -4805,6 +5105,12 @@ TRP_ROR_INTERSECT *get_best_covering_ror
   ROR_SCAN_INFO **ror_scans_end= tree->ror_scans_end;
   DBUG_ENTER("get_best_covering_ror_intersect");
 
+  // None of our tests enter this function
+  Opt_trace_object (param->thd->opt_trace).
+    add("get_best_covering_ror_intersect", true).
+    add("untested_code", true).
+    add("need_tracing",true);
+
   if (!param->thd->optimizer_switch_flag(OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT))
     DBUG_RETURN(NULL);
 
@@ -4964,9 +5270,7 @@ static TRP_RANGE *get_key_scans_params(P
   */
   DBUG_EXECUTE("info", print_sel_tree(param, tree, &tree->keys_map,
                                       "tree scans"););
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-  Opt_trace_object oto1(param->thd->opt_trace, "index_scans_parameters");
-#endif
+  Opt_trace_array ota(param->thd->opt_trace, "range_scan_alternatives");
 
   tree->ror_scans_map.clear_all();
   tree->n_ror_scans= 0;
@@ -4986,42 +5290,38 @@ static TRP_RANGE *get_key_scans_params(P
       bool read_index_only= index_read_must_be_used ? TRUE :
                             (bool) param->table->covering_keys.is_set(keynr);
 
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-      Opt_trace_object oto2(param->thd->opt_trace, "range_scan");
-      oto2.add(param->table->key_info[keynr].name, "index");
-#endif
+      Opt_trace_object trace_idx(param->thd->opt_trace);
+      trace_idx.add("index", param->table->key_info[keynr].name);
+
       found_records= check_quick_select(param, idx, read_index_only, *key,
                                         update_tbl_stats, &mrr_flags,
                                         &buf_size, &cost);
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-      oto2.add(read_index_only, "index_only").add(found_records, "records");
-#endif
+      trace_idx.add("index_only", read_index_only).
+        add("records", found_records).
+        add("cost", cost.total_cost());
 
       if ((found_records != HA_POS_ERROR) && param->is_ror_scan)
       {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-        oto2.add(true, "rowid_ordered");
-#endif
+        trace_idx.add("rowid_ordered", true);
         tree->n_ror_scans++;
         tree->ror_scans_map.set_bit(idx);
       }
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
       else
-        oto2.add(false, "rowid_ordered");
-#endif
+        trace_idx.add("rowid_ordered", false);
 
       if (found_records != HA_POS_ERROR &&
           read_time > (found_read_time= cost.total_cost()))
       {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-        oto2.add(found_read_time, "cost").add(true, "chosen");
-#endif
+        trace_idx.add("chosen", true);
         read_time=    found_read_time;
         best_records= found_records;
         key_to_read=  key;
         best_mrr_flags= mrr_flags;
         best_buf_size=  buf_size;
       }
+      else
+        trace_idx.add("chosen", false).add("cause", "higher_cost");
+
     }
   }
 
@@ -5037,10 +5337,6 @@ static TRP_RANGE *get_key_scans_params(P
       read_plan->is_ror= tree->ror_scans_map.is_set(idx);
       read_plan->read_cost= read_time;
       read_plan->mrr_buf_size= best_buf_size;
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-      oto1.add(param->table->key_info[param->real_keynr[idx]].name,
-                "index_for_best_range_access");
-#endif
       //DBUG_PRINT("info",
       //           ("Returning range plan for key %s, cost %g, records %lu",
       //            param->table->key_info[param->real_keynr[idx]].name,
@@ -5100,10 +5396,12 @@ QUICK_SELECT_I *TRP_ROR_INTERSECT::make_
                                              "creating ROR-intersect",
                                              first_scan, last_scan););
     alloc= parent_alloc? parent_alloc: &quick_intrsect->alloc;
-    for (; first_scan != last_scan;++first_scan)
+    for (st_ror_scan_info **current= first_scan; 
+         current != last_scan; 
+         current++)
     {
-      if (!(quick= get_quick_select(param, (*first_scan)->idx,
-                                    (*first_scan)->sel_arg,
+      if (!(quick= get_quick_select(param, (*current)->idx,
+                                    (*current)->sel_arg,
                                     HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED,
                                     0, alloc)) ||
           quick_intrsect->push_quick_back(quick))
@@ -7632,8 +7930,28 @@ range_seq_t sel_arg_range_seq_init(void 
 }
 
 
-static void step_down_to(SEL_ARG_RANGE_SEQ *arg, SEL_ARG *key_tree)
+static void step_down_to(String *s, SEL_ARG_RANGE_SEQ *arg, SEL_ARG *key_tree)
 {
+
+  if (arg->param->thd->opt_trace && arg->param->thd->opt_trace->is_started())
+  {
+    /* Stepping down will append the range for the current keypart (in
+       key_tree) to seq. Trace range here since this is where it is
+       human readable. 
+    */
+    KEY_PART_INFO *key_part= 
+      arg->param->table->key_info[arg->real_keyno].key_part+key_tree->part;
+      
+    uint16 length= key_part->length;
+    append_range(s,
+                key_part,
+                key_tree->min_value,
+                length,
+                key_tree->max_value,
+                length,
+                key_tree->min_flag | key_tree->max_flag);
+  }
+
   RANGE_SEQ_ENTRY *cur= &arg->stack[arg->i+1];
   RANGE_SEQ_ENTRY *prev= &arg->stack[arg->i];
   
@@ -7691,6 +8009,8 @@ uint sel_arg_range_seq_next(range_seq_t 
 {
   SEL_ARG *key_tree;
   SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)rseq;
+  String key_range_trace;
+
   if (seq->at_start)
   {
     key_tree= seq->start;
@@ -7706,7 +8026,7 @@ uint sel_arg_range_seq_next(range_seq_t 
   {
     //step down; (update the tuple, we'll step right and stay there)
     seq->i--;
-    step_down_to(seq, key_tree->next);
+    step_down_to(&key_range_trace, seq, key_tree->next);
     key_tree= key_tree->next;
     seq->param->is_ror_scan= FALSE;
     goto walk_right_n_up;
@@ -7727,7 +8047,7 @@ uint sel_arg_range_seq_next(range_seq_t 
     {
       // Step down; update the tuple
       seq->i--;
-      step_down_to(seq, key_tree->next);
+      step_down_to(&key_range_trace, seq, key_tree->next);
       key_tree= key_tree->next;
       seq->param->is_ror_scan= FALSE;
       break;
@@ -7781,7 +8101,7 @@ walk_up_n_right:
       /* Step up */
       key_tree= key_tree->prev;
     }
-    step_down_to(seq, key_tree);
+    step_down_to(&key_range_trace, seq, key_tree);
   }
 
   /* Ok got a tuple */
@@ -7839,17 +8159,18 @@ walk_up_n_right:
         seq->param->is_ror_scan= FALSE;
     }
   }
-  OPT_TRACE2(seq->param->thd->opt_trace,
-             print_range(seq->param->thd->opt_trace,
-                         seq->param->table->key_info[seq->real_keyno].key_part,
-                         range->start_key.key,
-                         range->start_key.length,
-                         range->end_key.key,
-                         range->end_key.length,
-                         cur->min_key_flag | cur->max_key_flag));
 
   seq->param->range_count++;
   seq->param->max_key_part=max(seq->param->max_key_part,key_tree->part);
+
+  if (key_range_trace.length())
+  {
+    DBUG_ASSERT(seq->param->thd->opt_trace);
+    DBUG_ASSERT(seq->param->thd->opt_trace->is_started());
+    Opt_trace_array *trace_range= 
+      (Opt_trace_array*)seq->param->thd->opt_trace->get_current_struct();
+    trace_range->add(key_range_trace.c_ptr());
+  }
   return 0;
 }
 
@@ -9722,14 +10043,29 @@ get_best_group_min_max(PARAM *param, SEL
 
   DBUG_ENTER("get_best_group_min_max");
 
+  Opt_trace_object trace_group(thd->opt_trace, "group_index_range");
+
   /* Perform few 'cheap' tests whether this access method is applicable. */
   if (!join)
+  {
+    trace_group.add("chosen", false).add("cause", "no_join");
     DBUG_RETURN(NULL);        /* This is not a select statement. */
-  if ((join->tables != 1) ||  /* The query must reference one table. */
-      (join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
+  }
+  if (join->tables != 1)   /* The query must reference one table. */
+  {
+    trace_group.add("chosen", false).add("cause", "not_single_table");
     DBUG_RETURN(NULL);
+  }
+  if (join->select_lex->olap == ROLLUP_TYPE) /* Check (B3) for ROLLUP */
+  {
+    trace_group.add("chosen", false).add("cause", "is_rollup");
+    DBUG_RETURN(NULL);
+  }
   if (table->s->keys == 0)        /* There are no indexes to use. */
+  {
+    trace_group.add("chosen", false).add("cause", "no_index");
     DBUG_RETURN(NULL);
+  }
 
   /* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
   if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
@@ -9741,7 +10077,10 @@ get_best_group_min_max(PARAM *param, SEL
   if ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
       (!join->select_distinct) &&
       !is_agg_distinct)
+  {
+    trace_group.add("chosen", false).add("cause", "not_group_by_or_distinct");
     DBUG_RETURN(NULL);
+  }
   /* Analyze the query in more detail. */
 
   if (join->sum_funcs[0])
@@ -9759,7 +10098,11 @@ get_best_group_min_max(PARAM *param, SEL
                min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC)
         continue;
       else
+      {
+        trace_group.add("chosen", false).
+          add("cause", "not_applicable_aggregate_function");
         DBUG_RETURN(NULL);
+      }
 
       /* The argument of MIN/MAX. */
       Item *expr= min_max_item->get_arg(0)->real_item();
@@ -9777,6 +10120,7 @@ get_best_group_min_max(PARAM *param, SEL
   /* Check (SA5). */
   if (join->select_distinct)
   {
+    trace_group.add("is_distinct_query", true);
     while ((item= select_items_it++))
     {
       if (item->real_item()->type() != Item::FIELD_ITEM)
@@ -9788,7 +10132,11 @@ get_best_group_min_max(PARAM *param, SEL
   for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next)
   {
     if ((*tmp_group->item)->real_item()->type() != Item::FIELD_ITEM)
+    {
+      trace_group.add("chosen", false).
+        add("cause", "group_field_is_expression");
       DBUG_RETURN(NULL);
+    }
   }
 
   /*
@@ -9810,9 +10158,12 @@ get_best_group_min_max(PARAM *param, SEL
   ha_rows cur_quick_prefix_records= 0;
   uint cur_param_idx=MAX_KEY;
 
+  Opt_trace_array ota(thd->opt_trace, "potential_group_range_indices");
   for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ;
        cur_index_info++, cur_index++)
   {
+    Opt_trace_object trace_idx(thd->opt_trace);
+    trace_idx.add("index", table->key_info[cur_index].name);
     KEY_PART_INFO *cur_part;
     KEY_PART_INFO *end_part; /* Last part for loops. */
     /* Last index part. */
@@ -9832,7 +10183,10 @@ get_best_group_min_max(PARAM *param, SEL
     
     /* Check (B1) - if current index is covering. */
     if (!table->covering_keys.is_set(cur_index))
+    {
+      trace_idx.add("usable", false).add("covering_index", false);
       goto next_index;
+    }
 
     /*
       If the current storage manager is such that it appends the primary key to
@@ -9856,9 +10210,13 @@ get_best_group_min_max(PARAM *param, SEL
         */
         if (bitmap_is_set(table->read_set, cur_field->field_index) &&
             !cur_field->part_of_key_not_clustered.is_set(cur_index))
+        {
+          trace_idx.add("usable", false).add("covering_index", false);
           goto next_index;                  // Field was not part of key
+        }
       }
     }
+    trace_idx.add("covering", true);
 
     /*
       Check (GA1) for GROUP BY queries.
@@ -9887,9 +10245,14 @@ get_best_group_min_max(PARAM *param, SEL
           used_key_parts_map.set_bit(max_key_part);
         }
         else
+        {
+          trace_idx.add("usable", false).
+            add("cause", "group_attribute_not_prefix_in_index");
           goto next_index;
+        }
       }
     }
+
     /*
       Check (GA2) if this is a DISTINCT query.
       If GA2, then Store a new ORDER object in group_fields_array at the
@@ -9916,7 +10279,10 @@ get_best_group_min_max(PARAM *param, SEL
 
         /* not doing loose index scan for derived tables */
         if (!item_field->field)
+        {
+          trace_idx.add("usable", false);
           goto next_index;
+        }
 
         /* Find the order of the key part in the index. */
         key_part_nr= get_field_keypart(cur_index_info, item_field->field);
@@ -9928,7 +10294,11 @@ get_best_group_min_max(PARAM *param, SEL
           continue;
         if (key_part_nr < 1 ||
             (!is_agg_distinct && key_part_nr > join->fields_list.elements))
+        {
+          trace_idx.add("usable", false).
+            add("cause", "select_attribute_not_prefix_in_index");
           goto next_index;
+        }
         cur_part= cur_index_info->key_part + key_part_nr - 1;
         cur_group_prefix_len+= cur_part->store_length;
         used_key_parts_map.set_bit(key_part_nr);
@@ -9953,7 +10323,11 @@ get_best_group_min_max(PARAM *param, SEL
     {
       key_part_nr= get_field_keypart(cur_index_info, min_max_arg_item->field);
       if (key_part_nr <= cur_group_key_parts)
+      {
+        trace_idx.add("usable", false).
+          add("cause", "aggregate_column_not_suffix_in_idx");
         goto next_index;
+      }
       min_max_arg_part= cur_index_info->key_part + key_part_nr - 1;
     }
 
@@ -9994,7 +10368,10 @@ get_best_group_min_max(PARAM *param, SEL
                                     last_part, thd, cur_key_infix, 
                                     &cur_key_infix_len,
                                     &first_non_infix_part))
+        {
+          trace_idx.add("usable", false).add("cause", "nonconst_equality_gap_attribute");
           goto next_index;
+        }
       }
       else if (min_max_arg_part &&
                (min_max_arg_part - first_non_group_part > 0))
@@ -10003,6 +10380,7 @@ get_best_group_min_max(PARAM *param, SEL
           There is a gap but no range tree, thus no predicates at all for the
           non-group keyparts.
         */
+        trace_idx.add("usable", false).add("cause", "no_nongroup_keypart_predicate");
         goto next_index;
       }
       else if (first_non_group_part && join->conds)
@@ -10026,7 +10404,11 @@ get_best_group_min_max(PARAM *param, SEL
         /* Check if cur_part is referenced in the WHERE clause. */
         if (join->conds->walk(&Item::find_item_in_field_list_processor, 0,
                               (uchar*) key_part_range))
+        {
+          trace_idx.add("usable", false).
+            add("cause", "indexpart_reference_from_where_clause");
           goto next_index;
+        }
       }
     }
 
@@ -10041,7 +10423,11 @@ get_best_group_min_max(PARAM *param, SEL
       for (; cur_part != last_part; cur_part++)
       {
         if (bitmap_is_set(table->read_set, cur_part->field->field_index))
+        {
+          trace_idx.add("usable", false).
+            add("cause", "keypart_after_infix_in_query");
           goto next_index;
+        }
       }
     }
 
@@ -10075,6 +10461,8 @@ get_best_group_min_max(PARAM *param, SEL
       Do not compare doubles directly because they may have different
       representations (64 vs. 80 bits).
     */
+    trace_idx.add("records", cur_records);
+    trace_idx.add("cost", cur_read_cost);
     if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost))
     {
       index_info= cur_index_info;
@@ -10102,8 +10490,11 @@ get_best_group_min_max(PARAM *param, SEL
       !check_group_min_max_predicates(join->conds, min_max_arg_item,
                                       (index_info->flags & HA_SPATIAL) ?
                                       Field::itMBR : Field::itRAW))
+  {
+    trace_group.add("usable",false).
+      add("cause", "unsupported_predicate_on_agg_attribute");
     DBUG_RETURN(NULL);
-
+  }
   /* The query passes all tests, so construct a new TRP object. */
   read_plan= new (param->mem_root)
                  TRP_GROUP_MIN_MAX(have_min, have_max, is_agg_distinct,
@@ -10123,6 +10514,7 @@ get_best_group_min_max(PARAM *param, SEL
     read_plan->records=   best_records;
     if (read_time < best_read_cost && is_agg_distinct)
     {
+      trace_group.add("is_index_scan", true);
       read_plan->read_cost= 0;
       read_plan->use_index_scan();
     }
@@ -11782,7 +12174,7 @@ static void print_sel_tree(PARAM *param,
     tmp.append(STRING_WITH_LEN("(empty)"));
 
   DBUG_PRINT("info", ("SEL_TREE: %p (%s)  scans: %s", tree, msg, tmp.ptr()));
-  fprintf(DBUG_FILE,"SEL_TREE: %p (%s)  scans: %s", tree, msg, tmp.ptr());
+  fprintf(DBUG_FILE,"SEL_TREE: %p (%s)  scans: %s\n", tree, msg, tmp.ptr());
   DBUG_VOID_RETURN;
 }
 
@@ -11822,87 +12214,48 @@ static void print_ror_scans_arr(TABLE *t
 
 #if !defined(DBUG_OFF) || defined(OPTIMIZER_TRACE)
 
-/*
-  Print a key into a stream
-
-  SYNOPSIS
-    key_part     Index components description
-    key          Key tuple
-    used_length  Key tuple length
-*/
+/**
+  Append range info to a string
 
-static void
-print_key2(String *out, KEY_PART_INFO *key_part, const uchar *key, 
-           uint used_length)
+  @param[in,out] out          String the range info is appended to
+  @param[in]     key_parts    Index components description
+  @param[in]     min_key      Key tuple describing lower bound of range
+  @param[in]     min_length   Length of min_key
+  @param[in]     max_key      Key tuple describing upper bound of range
+  @param[in]     max_length   Length of max_key
+  @param[in]     flag         Key range flags defining what min_key
+                              and max_key represent @see my_base.h
+ */
+static void append_range(String *out, 
+                         KEY_PART_INFO *key_parts,
+                         const uchar *min_key, uint16 min_length,
+                         const uchar *max_key, uint16 max_length, 
+                         uint flag)
 {
-  const uchar *key_end= key+used_length;
-  String tmp;
-  uint store_length;
-  TABLE *table= key_part->field->table;
-  my_bitmap_map *old_sets[2];
+  if (out->length() > 0)
+    out->append(" : ");
 
-  dbug_tmp_use_all_columns(table, old_sets, table->read_set, table->write_set);
-
-  for (; key < key_end; key+=store_length, key_part++)
-  {
-    Field *field=      key_part->field;
-    store_length= key_part->store_length;
-
-    if (field->real_maybe_null())
-    {
-      if (*key)
-      {
-	out->append("NULL", 4);
-	continue;
-      }
-      key++;					// Skip null byte
-      store_length--;
-    }
-    field->set_key_image(key, key_part->length);
-    if (field->type() == MYSQL_TYPE_BIT)
-      (void) field->val_int_as_str(&tmp, 1);
-    else
-      field->val_str(&tmp);
-    out->append(tmp.ptr(), tmp.length());
-    if (key+store_length < key_end)
-      out->append("'/",1);
-  }
-  dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_sets);
-}
-
-
-static void print_range(Opt_trace_context *out, KEY_PART_INFO *key_parts,
-                        const uchar *min_key, uint16 min_length,
-                        const uchar *max_key, uint16 max_length, 
-                        uint flag)
-{
-  String tmp;
   if (!(flag & NO_MIN_RANGE))
   {
-    print_key2(&tmp, key_parts, min_key, min_length);
+    print_key2(out, key_parts, min_key, min_length);
     if (flag & NEAR_MIN)
-      tmp.append(" < ");
+      out->append(" < ");
     else
-      tmp.append(" <= ");
+      out->append(" <= ");
   }
 
-  tmp.append("X");
+  out->append(key_parts->field->field_name);
 
   if (!(flag & NO_MAX_RANGE))
   {
     if (flag & NEAR_MAX)
-      tmp.append(" < ");
+      out->append(" < ");
     else
-      tmp.append(" <= ");
-    print_key2(&tmp, key_parts, max_key, max_length);
+      out->append(" <= ");
+    print_key2(out, key_parts, max_key, max_length);
   }
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-  OPT_TRACE(out, add(tmp.c_ptr()));
-#endif
 }
 
-
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
 static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg)
 {
   char buf[MAX_KEY/8+1];
@@ -11927,20 +12280,17 @@ static void print_quick(QUICK_SELECT_I *
   DBUG_UNLOCK_FILE;
   DBUG_VOID_RETURN;
 }
-#endif
-
 
 void QUICK_RANGE_SELECT::dbug_dump(int indent, bool verbose)
 {
   Opt_trace_context *out= current_thd->opt_trace;
   /* purecov: begin inspected */
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-  Opt_trace_object oto(out, "range_select");
-  oto.add(head->key_info[index].name, "index").
-    add(static_cast<ulonglong>(max_used_key_length), "key_length");
+  Opt_trace_object oto(out, "range_scan");
+  oto.add("index", head->key_info[index].name).
+    add("key_length", max_used_key_length).
+    add("used_keyparts", used_key_parts);
 
-  Opt_trace_array ota(out, "ranges");
-#endif
+  Opt_trace_array trace_range(out, "ranges");
   if (TRUE)
   {
     QUICK_RANGE *range;
@@ -11948,72 +12298,66 @@ void QUICK_RANGE_SELECT::dbug_dump(int i
     QUICK_RANGE **end_range= pr + ranges.elements;
     for (; pr != end_range; ++pr)
     {
+      String range_info;
       range= *pr;
-      print_range(out, head->key_info[index].key_part,
-                  range->min_key, range->min_length, 
-                  range->max_key, range->max_length,
-                  range->flag);
+      append_range(&range_info, head->key_info[index].key_part,
+                        range->min_key, range->min_length, 
+                        range->max_key, range->max_length,
+                        range->flag);
+      trace_range.add(range_info.c_ptr());
     }
   }
   /* purecov: end */    
 }
 
-
 void QUICK_INDEX_MERGE_SELECT::dbug_dump(int indent, bool verbose)
 {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
   Opt_trace_context *out= current_thd->opt_trace;
-#endif
   List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
   QUICK_RANGE_SELECT *quick;
   /* purecov: begin inspected */
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-  Opt_trace_object oto(out, "index_merge_sort_union");
-#endif
+  Opt_trace_array ota(out, "index_merge");
   while ((quick= it++))
+  {
+    Opt_trace_object wrapper(out);
     quick->dbug_dump(indent+2, verbose);
+  }
   if (pk_quick_select)
   {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
     Opt_trace_object oto2(out, "clustered_pk_scan");
-#endif
     pk_quick_select->dbug_dump(indent+2, verbose);
   }
 }
 
 void QUICK_ROR_INTERSECT_SELECT::dbug_dump(int indent, bool verbose)
 {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
   Opt_trace_context *out= current_thd->opt_trace;
-#endif
   List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
   QUICK_RANGE_SELECT *quick;
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-  Opt_trace_object oto(out, "index_merge_intersect");
-#endif
+  Opt_trace_array ota(out, "index_roworder_intersect");
   while ((quick= it++))
+  {
+    Opt_trace_object wrapper(out);
     quick->dbug_dump(indent+2, verbose);
+  }
   if (cpk_quick)
   {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
     Opt_trace_object oto2(out, "clustered_pk_scan");
-#endif
     cpk_quick->dbug_dump(indent+2, verbose);
   }
 }
 
 void QUICK_ROR_UNION_SELECT::dbug_dump(int indent, bool verbose)
 {
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
   Opt_trace_context *out= current_thd->opt_trace;
-#endif
   List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
   QUICK_SELECT_I *quick;
-#ifndef NO_OPT_TRACE_FOR_RANGE_OPT
-  Opt_trace_object oto(out, "index_merge_sort_union_intersect");
-#endif
+  Opt_trace_array ota(out, "index_roworder_union");
   while ((quick= it++))
+  {
+    Opt_trace_object wrapper(out);
     quick->dbug_dump(indent+2, verbose);
+  }
 }
 
 
@@ -12039,6 +12383,11 @@ void QUICK_ROR_UNION_SELECT::dbug_dump(i
 
 void QUICK_GROUP_MIN_MAX_SELECT::dbug_dump(int indent, bool verbose)
 {
+  Opt_trace_context *out= current_thd->opt_trace;
+  Opt_trace_object oto(out, "index_group");
+  oto.add("index", index_info->name).
+    add("key_length", max_used_key_length);
+
   fprintf(DBUG_FILE,
           "%*squick_group_min_max_select: index %s (%d), length: %d\n",
 	  indent, "", index_info->name, index, max_used_key_length);

=== modified file 'sql/opt_range.h'
--- a/sql/opt_range.h	2010-08-05 13:51:44 +0000
+++ b/sql/opt_range.h	2010-10-07 09:02:31 +0000
@@ -33,6 +33,7 @@
 */
 #include "sql_class.h"                          // set_var.h: THD
 #include "set_var.h"                            /* Item */
+#include "opt_trace.h"
 
 class JOIN;
 class Item_sum;
@@ -863,6 +864,14 @@ class SQL_SELECT :public Sql_alloc {
   bool check_quick(THD *thd, bool force_quick_range, ha_rows limit)
   {
     key_map tmp(key_map::ALL_BITS);
+
+    /* Entrypoint for inser/update/deletes with condition.
+       test_quick_select adds tracing with keys, and we are currently
+       in a trace array that does not accept keys. Todo: move this
+       wrapper trace object to sql_insert/update/delete where it is
+       more meaningful.
+    */
+    Opt_trace_object wrapper(thd->opt_trace); 
     return test_quick_select(thd, tmp, 0, limit, force_quick_range, FALSE) < 0;
   }
   inline bool skip_record(THD *thd, bool *skip_record)

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-10-05 13:19:55 +0000
+++ b/sql/sql_select.cc	2010-10-07 09:02:31 +0000
@@ -259,6 +259,10 @@ void select_describe(JOIN *join, bool ne
 			    bool distinct, const char *message=NullS);
 static Item *remove_additional_cond(Item* conds);
 static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab);
+static void trace_indices_added_group_distinct(THD *thd, 
+                                               JOIN_TAB *join_tab,
+                                               const key_map new_keys, 
+                                               char* cause);
 static bool replace_subcondition(JOIN *join, Item **tree, 
                                  Item *old_cond, Item *new_cond,
                                  bool do_fix_fields);
@@ -4943,14 +4947,28 @@ make_join_statistics(JOIN *join, TABLE_L
 
       for (s= stat ; s < stat_end ; s++)
       {
+        Opt_trace_object trace_table(join->thd->opt_trace);
+        trace_table.add("table", s->table->alias);
         if (s->type == JT_SYSTEM || s->type == JT_CONST)
         {
+          trace_table.add("found_records", 1).
+            add("records", 1).
+            add("cost", 1).
+            add("worst_seeks", 1.0);
+
+          if (s->ref.key_parts)
+            trace_table.add("index", (s->table->key_info+ s->ref.key)->name);
+
+          trace_table.add("exit_find_best_accessplan", true);
+          if (s->type == JT_SYSTEM)
+            trace_table.add("cause", "is_system_table");
+          else
+            trace_table.add("cause", "is_const_table");
+
           /* Only one matching row */
           s->found_records= s->records= s->read_time=1; s->worst_seeks= 1.0;
           continue;
         }
-        Opt_trace_object oto1(join->thd->opt_trace);
-        oto1.add("table", s->table->alias);
         /* Approximate found rows and time to read them */
         s->found_records= s->records= s->table->file->stats.records;
         s->read_time= (ha_rows) s->table->file->scan_time();
@@ -4981,10 +4999,6 @@ make_join_statistics(JOIN *join, TABLE_L
              (s->table->pos_in_table_list->embedding &&             // (3)
               s->table->pos_in_table_list->embedding->sj_on_expr))) // (3)
         {
-#ifdef NO_OPT_TRACE_FOR_RANGE_OPT
-          Opt_trace_object(join->thd->opt_trace, "more_range_optimizer_trace").
-            add("TODO?", "yes!");
-#endif
           ha_rows records;
           SQL_SELECT *select;
           select= make_select(s->table, found_const_table_map,
@@ -5013,9 +5027,16 @@ make_join_statistics(JOIN *join, TABLE_L
             {
               /* Generate empty row */
               s->info= "Impossible ON condition";
+              trace_table.add("returning_empty_null_row", true).
+                add("cause", "impossible_on_condition");
               found_const_table_map|= s->table->map;
               s->type= JT_CONST;
               mark_as_null_row(s->table);		// All fields are NULL
+            } 
+            else 
+            {
+              trace_table.add("records", 0).
+                add("cause", "impossible_where_condition");
             }
           }
           if (records != HA_POS_ERROR)
@@ -6494,11 +6515,14 @@ add_group_and_distinct_keys(JOIN *join, 
   Item_field *cur_item;
   key_map possible_keys;
 
+  char* cause;
+
   if (join->group_list)
   { /* Collect all query fields referenced in the GROUP clause. */
     for (cur_group= join->group_list; cur_group; cur_group= cur_group->next)
       (*cur_group->item)->walk(&Item::collect_item_field_processor, 0,
                                (uchar*) &indexed_fields);
+    cause= (char*)"group_by\0";
   }
   else if (join->select_distinct)
   { /* Collect all query fields referenced in the SELECT clause. */
@@ -6508,10 +6532,12 @@ add_group_and_distinct_keys(JOIN *join, 
     while ((item= select_items_it++))
       item->walk(&Item::collect_item_field_processor, 0,
                  (uchar*) &indexed_fields);
+    cause= (char*)"distinct\0";
   }
   else if (is_indexed_agg_distinct(join, &indexed_fields))
   {
     join->sort_and_group= 1;
+    cause= (char*) "indexed_distinct_aggregate";
   }
   else
     return;
@@ -6527,8 +6553,49 @@ add_group_and_distinct_keys(JOIN *join, 
     possible_keys.intersect(cur_item->field->part_of_key);
   }
 
-  if (!possible_keys.is_clear_all())
+  if (!possible_keys.is_clear_all() && 
+      !(possible_keys == join_tab->const_keys))
+  {
+    trace_indices_added_group_distinct(join->thd, join_tab,
+                                       possible_keys, cause);
     join_tab->const_keys.merge(possible_keys);
+  }
+}
+
+/**
+  Print keys that were appended to join_tab->const_keys because they
+  can be used for GROUP BY or DISTINCT to the optimizer trace.
+
+  @param thd       Thread for the connection that submitted the query
+  @param join_tab  The table the indices cover
+  @param new_keys  The keys that are considered useful because they can 
+                   be used for GROUP BY or DISTINCT
+  @param cause     Zero-terminated string with reason for adding indices 
+                   to const_keys
+
+  @see add_group_and_distinct_keys()
+ */
+static void trace_indices_added_group_distinct(THD *thd, 
+                                               JOIN_TAB *join_tab,
+                                               const key_map new_keys, 
+                                               char* cause)
+{
+  // Do nothing if optimizer trace is not enabled
+  if (!thd->opt_trace || !thd->opt_trace->is_started())
+    return;
+
+  KEY *key_info= join_tab->table->key_info;
+  key_map existing_keys= join_tab->const_keys;
+  uint nokeys= join_tab->table->s->keys;
+  
+  Opt_trace_object trace_summary(thd->opt_trace, "const_keys_added");
+  {
+    Opt_trace_array trace_key(thd->opt_trace,"keys");
+    for (uint j=0 ; j < nokeys ; j++)
+      if (new_keys.is_set(j) && !existing_keys.is_set(j))
+        trace_key.add(key_info[j].name);
+  }
+  trace_summary.add("cause", cause);
 }
 
 
@@ -6970,8 +7037,8 @@ best_access_path(JOIN      *join,
       loose_scan_opt.next_ref_key();
       DBUG_PRINT("info", ("Considering ref access on key %s",
                           keyuse->table->key_info[keyuse->key].name));
-      Opt_trace_object oto1(thd->opt_trace);
-      oto1.add("access_type", "index").add("index", keyinfo->name);
+      Opt_trace_object trace_access_idx(thd->opt_trace);
+      trace_access_idx.add("access_type", "index").add("index", keyinfo->name);
 
       /* 
          True if we find some keys from the range optimizer that match more
@@ -7027,7 +7094,7 @@ best_access_path(JOIN      *join,
       */
       if (!found_part && !ft_key && !loose_scan_opt.have_a_case())
       {
-        oto1.add("usable", false);
+        trace_access_idx.add("usable", false);
         goto done_with_index;                  // Nothing usable found
       }
 
@@ -7306,7 +7373,7 @@ best_access_path(JOIN      *join,
         loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp);
 
       } /* not ft_key */
-      oto1.add("cost", tmp).add("records", records);
+      trace_access_idx.add("records", records).add("cost", tmp);
       /** @todo trace quick_matches_more_parts etc? */
       if (tmp < best_time - records/(double) TIME_FOR_COMPARE ||
           (quick_matches_more_parts && 
@@ -7321,13 +7388,13 @@ best_access_path(JOIN      *join,
         best_ref_depends_map= found_ref;
       }
   done_with_index:
-      oto1.add("chosen", best_key == start_key);
+      trace_access_idx.add("chosen", best_key == start_key);
     } /* for each key */
     records= best_records;
   }
 
-  Opt_trace_object oto1(thd->opt_trace);
-  oto1.add("access_type", "table scan");
+  Opt_trace_object trace_access_scan(thd->opt_trace);
+  trace_access_scan.add("access_type", "scan");
   /*
     Don't test table scan if it can't be better.
     Prefer key lookup if we would use the same key for scanning.
@@ -7358,27 +7425,31 @@ best_access_path(JOIN      *join,
   */
   if (!(records >= s->found_records || best > s->read_time))            // (1)
   {
-    oto1.add("cost", s->read_time).add("records", s->found_records);
+    trace_access_scan.add("cost", s->read_time).
+      add("records", s->found_records).
+      add("chosen", false);
     goto skip_table_scan;
   }
 
   if ((s->quick && best_key && s->quick->index == best_key->key &&      // (2)
        best_max_key_part >= s->table->quick_key_parts[best_key->key]))  // (2)
   {
-    oto1.add("heuristic_index_must_be_cheaper", true);
+    trace_access_scan.add("chosen", false).
+      add("cause", "heuristic_index_cheaper");
     goto skip_table_scan;
   }
 
   if (((s->table->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) &&     // (3)
        ! s->table->covering_keys.is_clear_all() && best_key && !s->quick))// (3)
   {
-    oto1.add("index_is_covering", true);
+    trace_access_scan.add("chosen", false).
+      add("cause", "covering_index_better_than_full_scan");
     goto skip_table_scan;
   }
 
   if ((s->table->force_index && best_key && !s->quick))                 // (4)
   {
-    oto1.add("FORCE_INDEX_used", true);
+    trace_access_scan.add("chosen", false).add("cause", "force_index");
     goto skip_table_scan;
   }
 
@@ -7411,6 +7482,7 @@ best_access_path(JOIN      *join,
 
     if (s->quick)
     {
+      trace_access_scan.add("using_range_access", true);
       /*
         For each record we:
         - read record range through 'quick'
@@ -7428,6 +7500,7 @@ best_access_path(JOIN      *join,
     }
     else
     {
+      trace_access_scan.add("using_range_access", false);
       /* Estimate cost of reading table. */
       if (s->table->force_index && !best_key)
         tmp= s->table->file->read_time(s->ref.key, 1, s->records);
@@ -7447,6 +7520,7 @@ best_access_path(JOIN      *join,
       }
       else
       {
+        trace_access_scan.add("using_join_cache", true);
         /*
           We read the table as many times as join buffer becomes full.
           It would be more exact to round the result of the division with
@@ -7466,7 +7540,8 @@ best_access_path(JOIN      *join,
       }
     }
 
-    oto1.add("cost", tmp).add("records", rows2double(rnd_records));
+    Opt_trace_object (thd->opt_trace, "with_where_cond_processing").
+      add("records", rows2double(rnd_records)).add("cost", tmp);
     /*
       We estimate the cost of evaluating WHERE clause for found records
       as record_count * rnd_records / TIME_FOR_COMPARE. This cost plus
@@ -7489,11 +7564,10 @@ best_access_path(JOIN      *join,
                                                join->outer_join)));
     }
   }
+  trace_access_scan.add("chosen", best_key == NULL);
 
 skip_table_scan:
 
-  oto1.add("chosen", best_key == NULL);
-
   /* Update the cost information for the current partial plan */
   pos->records_read= records;
   pos->read_time=    best;
@@ -7509,7 +7583,10 @@ skip_table_scan:
       idx == join->const_tables &&
       s->table == join->sort_by_table &&
       join->unit->select_limit_cnt >= records)
+  {
+    trace_access_scan.add("use_temp_table", true);
     join->sort_by_table= (TABLE*) 1;  // Must use temporary table
+  }
 
   DBUG_VOID_RETURN;
 }


Attachment: [text/bzr-bundle] bzr/jorgen.loland@oracle.com-20101007090231-gc6kgk1c7ppd1rgo.bundle
Thread
bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219) WL#5594Jorgen Loland7 Oct
  • Re: bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219)WL#5594Guilhem Bichot16 Oct
    • Re: bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219)WL#5594Jorgen Loland22 Oct
      • Re: bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219)WL#5594Guilhem Bichot10 Nov
        • Re: bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219)WL#5594Jorgen Loland12 Nov
          • Re: bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219)WL#5594Guilhem Bichot15 Nov
      • Re: bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219)WL#5594Guilhem Bichot7 Feb
        • Re: bzr commit into mysql-next-mr-bugfixing branch (jorgen.loland:3219)WL#5594Jorgen Loland8 Feb