|
| 1 | +--echo # |
| 2 | +--echo # Bug#18167648: WRONG RESULTS WITH PARTITIONING, INDEX_MERGE AND NO PK |
| 3 | +--echo # |
| 4 | +CREATE TABLE t1 |
| 5 | +(a smallint, |
| 6 | + b smallint, |
| 7 | + c smallint, |
| 8 | + KEY a (a), |
| 9 | + KEY b (b) |
| 10 | +) ENGINE=InnoDB |
| 11 | +PARTITION BY HASH(c) PARTITIONS 3; |
| 12 | + |
| 13 | +--echo # c will simulate DB_ROW_ID + force to chosen partition. |
| 14 | +--echo # c is unique so we can identify rows in the test. |
| 15 | +--echo # Fillers to make the optimizer choose index_merge_intersect/union: |
| 16 | +INSERT INTO t1 VALUES (1,1,1), (1,1,1+3), (1,1,1+6), (1,1,1+9); |
| 17 | +--echo # row N..N+3 |
| 18 | +INSERT INTO t1 VALUES (1,2,1+12), (2,2,2+15), (2,2,2+18), (1,2,3+21); |
| 19 | +--echo # More index matching rows for index_merge_intersect: N+4, N+5 |
| 20 | +INSERT INTO t1 VALUES (2,2,1+24); |
| 21 | +INSERT INTO t1 VALUES (2,1,1+27); |
| 22 | +ANALYZE TABLE t1; |
| 23 | + |
| 24 | +SET @old_opt_switch = @@session.optimizer_switch; |
| 25 | +SET SESSION optimizer_switch="index_merge=on"; |
| 26 | +SET SESSION optimizer_switch="index_merge_intersection=on"; |
| 27 | +SET SESSION optimizer_switch="index_merge_sort_union=off"; |
| 28 | +SET SESSION optimizer_switch="index_merge_union=off"; |
| 29 | +if ($use_optimizer_trace) |
| 30 | +{ |
| 31 | +SET SESSION optimizer_trace="enabled=on"; |
| 32 | +} |
| 33 | +EXPLAIN SELECT a,b,c FROM t1 WHERE b = 2 AND a = 2 AND c > 0 AND c < 100; |
| 34 | +if ($use_optimizer_trace) |
| 35 | +{ |
| 36 | +SELECT TRACE FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE; |
| 37 | +} |
| 38 | +# Before fix: |
| 39 | +# Index start of scan (ha_partition::handle_ordered_index_scan) |
| 40 | +# 0xNNN is the DB_ROW_ID, kind of internal global auto increment. |
| 41 | +# a reads row N+4 (0x208) from p1 c = 25 |
| 42 | +# a reads row N+1 (0x205) from p2 c = 17 |
| 43 | +# a returns row N+4, c = 25 (All same, first insert, no cmp of ref/DB_ROW_ID!) |
| 44 | +# b reads row N+3 (0x207) from p0 c = 24 |
| 45 | +# b reads row N (0x204) from p1 c = 13 |
| 46 | +# b reads row N+1 (0x205) from p2 c = 17 |
| 47 | +# b returns row N+3, c = 24 (All same, first insert, no cmp of ref/DB_ROW_ID!) |
| 48 | +# b skips to next (0x207 < 0x208) |
| 49 | +# b finds no more rows in p0. |
| 50 | +# b returns row from p2 (0x205) c = 17 |
| 51 | +# b skips to next row (0x205 < 0x208) |
| 52 | +# b reads row N+2 (0x206) from p2 c = 20 |
| 53 | +# b skips to next row (0x206 < 0x208) |
| 54 | +# b finds no more rows in p2. |
| 55 | +# b return row from p1 (0x204) c = 13 |
| 56 | +# b skips to next row (0x204 < 0x208) |
| 57 | +# b reads row N+4 (0x208) from p1 c = 25 |
| 58 | +# a == b Match found! |
| 59 | +# Fetches whole row for 0x208 (really p1 + 0x208) -> (2,2,25) |
| 60 | +# Continues with next a: |
| 61 | +# a reads row N+5 (0x209) from p1 c = 28 |
| 62 | +# No more match... |
| 63 | + |
| 64 | +SELECT a,b,c FROM t1 WHERE b = 2 AND a = 2 AND c > 0 AND c < 100; |
| 65 | +SET SESSION optimizer_switch="index_merge_intersection=off"; |
| 66 | +SELECT a,b,c FROM t1 WHERE b = 2 AND a = 2 AND c > 0 AND c < 100; |
| 67 | +EXPLAIN SELECT a,b,c FROM t1 WHERE b = 2 AND a = 2 AND c > 0 AND c < 100; |
| 68 | + |
| 69 | +--echo # Adding more fillers to get index_merge_union |
| 70 | +INSERT INTO t1 VALUES (1,1,1+30), (1,1,1+33), (1,1,1+36), (1,1,1+39), |
| 71 | +(1,1,1+42), (1,1,1+45), (1,1,1+48), (1,1,1+51), (1,1,1+54), (1,1,1+57), |
| 72 | +(1,1,1+60), (1,1,1+63), (1,1,1+66), (1,1,1+69), (1,1,1+72), (1,1,1+75), |
| 73 | +(1,1,1+78); |
| 74 | +ANALYZE TABLE t1; |
| 75 | +SET SESSION optimizer_switch="index_merge_union=on"; |
| 76 | +EXPLAIN SELECT a,b,c FROM t1 WHERE (b = 2 OR a = 2) AND c > 0 AND c < 100; |
| 77 | +if ($use_optimizer_trace) |
| 78 | +{ |
| 79 | +SELECT TRACE FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE; |
| 80 | +} |
| 81 | +# First there where a bug where index_init() was called with sorted=false :( |
| 82 | +# Before fix of secondary sort in ha_partition: |
| 83 | +# b reads row N+3 (0x207) from p0 c = 24 |
| 84 | +# b reads row N (0x204) from p1 c = 13 |
| 85 | +# b reads row N+1 (0x205) from p2 c = 17 |
| 86 | +# b returns row N+3, c = 24 (All same, first insert, no cmp of ref/DB_ROW_ID!) |
| 87 | +# a reads row N+4 (0x208) from p1 c = 25 |
| 88 | +# a reads row N+1 (0x205) from p2 c = 17 |
| 89 | +# a returns row N+4, c = 25 (All same, first insert, no cmp of ref/DB_ROW_ID!) |
| 90 | + |
| 91 | +# first row from both indexes done, first is b, 0x207 c = 24 |
| 92 | +# Get next from b |
| 93 | +# b finds no more rows in p0. |
| 94 | +# b returns row from p2 (0x205) c = 17 |
| 95 | +# Fetching whole row for (0x207) c = 24 (1,2,24) and sends it |
| 96 | +# b reads row N+2 (0x206) from p2 c = 20 |
| 97 | +# b returns row from p2 (0x206) c = 20 |
| 98 | +# No duplicate (0x206 != 0x208) |
| 99 | +# Fetching whole row for (0x205) c = 17 (2,2,17) and sends it |
| 100 | +# b finds no more rows in p2 |
| 101 | +# b returns row from p1 (0x204) c = 13 |
| 102 | +# No duplicate (0x205 != 0x206) |
| 103 | +# Fetching whole row for (0x206) c = 20 (2,2,20) and sends it |
| 104 | +# b reads row N+4 (0x208) from p1 c = 25 |
| 105 | +# b returns row from p1 (0x208) c = 25 |
| 106 | +# No duplicate (0x204 != 0x206) |
| 107 | +# Fetching whole row for (0x204) c = 13 (1,2,13) and sends it |
| 108 | +# Fetching whole row for (0x208) c = 25 (2,2,25) |
| 109 | +# a reads row N+5 (0x209) from p1 c = 28 |
| 110 | +# a returns row from p1 (0x209) c = 28 |
| 111 | +# Duplicate (0x209 == 0x209) |
| 112 | +# a returns row from p2 (0x205) |
| 113 | +# Fetching whole row for (0x209) c = 28 (2,1,28) |
| 114 | +# a reads row N+2 (0x206) from p2 c = 20 |
| 115 | +# Fetching whole row for (0x205) c = 17 (2,2,17) |
| 116 | +# Fetching whole row for (0x206) c = 20 (2,2,20) |
| 117 | + |
| 118 | +SELECT a,b,c FROM t1 WHERE (b = 2 OR a = 2) AND c > 0 AND c < 100; |
| 119 | +SET SESSION optimizer_switch="index_merge_union=off"; |
| 120 | +SELECT a,b,c FROM t1 WHERE (b = 2 OR a = 2) AND c > 0 AND c < 100; |
| 121 | +EXPLAIN SELECT a,b,c FROM t1 WHERE (b = 2 OR a = 2) AND c > 0 AND c < 100; |
| 122 | + |
| 123 | +--echo Insert a few more rows to trigger sort_union |
| 124 | +INSERT INTO t1 VALUES (1,1,1+81), (1,1,1+84), (1,1,1+87), (1,1,1+90), |
| 125 | +(1,1,1+93); |
| 126 | +ANALYZE TABLE t1; |
| 127 | +SET SESSION optimizer_switch="index_merge_sort_union=on"; |
| 128 | +EXPLAIN SELECT a,b,c FROM t1 WHERE (b >= 2 OR a >= 2) AND c > 0 AND c < 100; |
| 129 | +if ($use_optimizer_trace) |
| 130 | +{ |
| 131 | +SELECT TRACE FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE; |
| 132 | +SET SESSION optimizer_trace="enabled=off"; |
| 133 | +} |
| 134 | +--echo # Not affected, added for completeness... |
| 135 | +SELECT a,b,c FROM t1 WHERE (b >= 2 OR a >= 2) AND c > 0 AND c < 100; |
| 136 | +SET SESSION optimizer_switch="index_merge_sort_union=off"; |
| 137 | +SELECT a,b,c FROM t1 WHERE (b >= 2 OR a >= 2) AND c > 0 AND c < 100; |
| 138 | +EXPLAIN SELECT a,b,c FROM t1 WHERE (b >= 2 OR a >= 2) AND c > 0 AND c < 100; |
| 139 | + |
| 140 | +SET @@session.optimizer_switch = @old_opt_switch; |
| 141 | +DROP TABLE t1; |
0 commit comments