|
553 | 553 |
|
554 | 554 | explain
|
555 | 555 | SELECT STRAIGHT_JOIN count(*) FROM
|
556 |
| - t1 JOIN t2 ON t2.a=t1.a where t2.uq IS NULL; |
| 556 | + t1 JOIN t2 FORCE INDEX FOR JOIN (ix) ON t2.a=t1.a where t2.uq IS NULL; |
557 | 557 | SELECT STRAIGHT_JOIN count(*) FROM
|
558 |
| - t1 JOIN t2 ON t2.a=t1.a where t2.uq IS NULL; |
| 558 | + t1 JOIN t2 FORCE INDEX FOR JOIN (ix) ON t2.a=t1.a where t2.uq IS NULL; |
559 | 559 |
|
560 | 560 | drop table t1,t2;
|
561 | 561 |
|
@@ -738,4 +738,108 @@ insert into t2 values (4);
|
738 | 738 | --echo #cleanup
|
739 | 739 | drop table t2, t1;
|
740 | 740 |
|
| 741 | + |
| 742 | +--echo # |
| 743 | +--echo # Bug#33317872 Incorrect Index selected leading to slower execution of queries |
| 744 | +--echo # |
| 745 | +--echo # When choosing between a Multi-range-read on an unique index, |
| 746 | +--echo # and a range scan on an ordered index, where few rows are expected |
| 747 | +--echo # to be returned, prefer the unique index. |
| 748 | +--echo # (An ordered index scan has higher cost, as all fragments are scanned) |
| 749 | +--echo # |
| 750 | + |
| 751 | +CREATE TABLE t ( |
| 752 | + delivery_id bigint unsigned NOT NULL AUTO_INCREMENT, |
| 753 | + msg_id int unsigned NOT NULL, |
| 754 | + auth_login_type char(1) DEFAULT NULL, |
| 755 | + auth_login_id varchar(64), |
| 756 | + PRIMARY KEY (delivery_id), |
| 757 | + UNIQUE KEY msg_id(msg_id,auth_login_type,auth_login_id), |
| 758 | + KEY auth_login_id(auth_login_id) |
| 759 | +) ENGINE=ndbcluster; |
| 760 | + |
| 761 | +disable_query_log; |
| 762 | + |
| 763 | +insert into t (msg_id, auth_login_type, auth_login_id) values |
| 764 | +(4866, '5', '91774132'), (4869, '5', '91884132'); |
| 765 | +insert into t (msg_id, auth_login_type, auth_login_id) values |
| 766 | +(4866, '5', '91774134'), (4869, '5', '91884134'); |
| 767 | + |
| 768 | +insert into t (msg_id, auth_login_type, auth_login_id) values |
| 769 | +(4866, '4', '91774133'), (4869, '4', '91884133'); |
| 770 | +insert into t (msg_id, auth_login_type, auth_login_id) values |
| 771 | +(4866, '6', '91774133'), (4869, '6', '91884133'); |
| 772 | + |
| 773 | +insert into t (msg_id, auth_login_type, auth_login_id) values |
| 774 | +(4865, '5', '91774133'), (4868, '5', '91774133'); |
| 775 | +insert into t (msg_id, auth_login_type, auth_login_id) values |
| 776 | +(4867, '5', '91774133'), (4870, '5', '91774133'); |
| 777 | +# ^^^ Add some more rows, none will match the query |
| 778 | + |
| 779 | +# Use these as base for filling in more rows |
| 780 | +insert into t (msg_id, auth_login_type, auth_login_id) select |
| 781 | + msg_id - 4800, auth_login_type, auth_login_id+10 from t; |
| 782 | + |
| 783 | +insert into t (msg_id, auth_login_type, auth_login_id) select |
| 784 | + msg_id + 1000, auth_login_type, auth_login_id+20 from t where msg_id < 100; |
| 785 | +insert into t (msg_id, auth_login_type, auth_login_id) select |
| 786 | + msg_id + 2000, auth_login_type, auth_login_id+30 from t where msg_id < 100; |
| 787 | +insert into t (msg_id, auth_login_type, auth_login_id) select |
| 788 | + msg_id + 3000, auth_login_type, auth_login_id+40 from t where msg_id < 100; |
| 789 | + |
| 790 | +insert into t (msg_id, auth_login_type, auth_login_id) select |
| 791 | + msg_id + 5000, auth_login_type, auth_login_id+50 from t where msg_id < 100; |
| 792 | +insert into t (msg_id, auth_login_type, auth_login_id) select |
| 793 | + msg_id + 6000, auth_login_type, auth_login_id+60 from t where msg_id < 100; |
| 794 | +insert into t (msg_id, auth_login_type, auth_login_id) select |
| 795 | + msg_id + 7000, auth_login_type, auth_login_id+70 from t where msg_id < 100; |
| 796 | + |
| 797 | + |
| 798 | +########################################## |
| 799 | +# Statistics is asynchronous: We can not predict when it |
| 800 | +# is available in the statistics cache, and thus which |
| 801 | +# statistics is being used for the query. Thus we |
| 802 | +# need to cheat: |
| 803 | +# |
| 804 | +# We 'analyze' without the rows to be select yet inserted. |
| 805 | +# -> statistics will predictable contain 0 rows to be returned. |
| 806 | +# Which is 'rounded' up to 2 rows, which are the lowest number of |
| 807 | +# rows allowed to be estimated from non unique indexes. |
| 808 | +# |
| 809 | +# Note that the estimated 2 rows is actually what _is_ in the table |
| 810 | +# as well, when we later insert these rows below! |
| 811 | + |
| 812 | +analyze table t; |
| 813 | +enable_query_log; |
| 814 | + |
| 815 | +########################################## |
| 816 | +# Then insert the rows we want returned, without being part of the statistics |
| 817 | +insert into t (msg_id, auth_login_type, auth_login_id) values |
| 818 | + (4866, '5', '81774133'), |
| 819 | + (4869, '5', '81774133'); |
| 820 | +# ^^^^ Rows we want from the query |
| 821 | + |
| 822 | +# optimizer trace, For debugging, or understanding of test case + bug: |
| 823 | +# |
| 824 | +# If enabled, we will find that optimizer first calculate the range-access |
| 825 | +# cost, using handler ::cost methods, and correctly find the msg_id to |
| 826 | +# have the lowest cost. |
| 827 | +# Possible REF-accesses are then investigated and estimated: However, these |
| 828 | +# cost estimates was 'pre-patch' based in an entirely different page/cache |
| 829 | +# cost metric, not being compare compatible with the former. A lower cost |
| 830 | +# was found for using REF access on auth_login_id index, incorrectly causing |
| 831 | +# this index to to be used for the table access. |
| 832 | +# |
| 833 | +#SET optimizer_trace_max_mem_size=1048576; # 1MB |
| 834 | +#SET end_markers_in_json=on; |
| 835 | +#SET optimizer_trace="enabled=on,one_line=off"; |
| 836 | + |
| 837 | +explain |
| 838 | + select * from t |
| 839 | + where auth_login_type='5' AND auth_login_id = '81774133' AND msg_id IN (4866,4869); |
| 840 | + |
| 841 | +#SELECT * FROM information_schema.optimizer_trace; |
| 842 | + |
| 843 | +drop table t; |
| 844 | + |
741 | 845 | # end of tests
|
0 commit comments