sql hint 不生效

想请问各位老师以下,为什么sql hint 指定index hash join 不生效,很奇怪


there are no matching table names for (s2) in optimizer hint /*+ INL_HASH_JOIN(s1, s2) */. Maybe you can use the table alias name
s2 匹配不到,其实s2是存在的

复现步骤如下:
create table s1(id int not null auto_increment primary key,a_date varchar(8),a_type varchar(8));
alter table s1 add index date_index(a_date);
create table s2(a_type varchar(8) primary key,a_flag varchar(1),a_s varchar(1));

insert into s1(a_date,a_type)values(‘20230421’,‘1000’);
insert into s1(a_date,a_type)values(‘20230422’,‘1001’);
insert into s1(a_date,a_type)values(‘20230421’,‘1002’);
insert into s1(a_date,a_type)values(‘20230422’,‘1003’);
insert into s1(a_date,a_type)values(‘20230421’,‘1004’);
insert into s1(a_date,a_type)values(‘20230420’,‘1004’);

insert into s2 values(‘1000’,‘1’,‘1’);
insert into s2 values(‘1001’,‘1’,‘2’);
insert into s2 values(‘1002’,‘1’,‘2’);
insert into s2 values(‘1004’,‘1’,‘2’);

select /*+ INL_HASH_JOIN(s1, s2) */ * from s1 where a_date=‘20230421’ and a_type in (select a_type from s2 where a_flag=‘1’);

子查询

跟这个有关系嘛

没亲测,但感觉是hint的查询块引用描述问题
你改成下面这样试下:
select /*+ INL_HASH_JOIN(@sel_1 s1, s3) */ * from s1 where a_date=‘20230421’ and a_type in (select a_type from s2 where a_flag=‘1’) s3;

话不多说,indexjoin 和indexhashjoin都是依赖连接字段的索引

| Warning | 1815 | Optimizer Hint /*+ INL_HASH_JOIN(s1, s2) */ is inapplicable

warning里面已经提示了。

ALTER TABLE s1 ADD INDEX type_index(a_type);
加个索引就行,s1上连接字段上没有连接字段上的索引。

大佬,我把s1 的a_date,a_type 建个索引就好了
但是请问为什么呢
但是为啥还有warnning

因为你用了子查询,如果这样写
EXPLAIN ANALYZE SELECT /*+ INL_HASH_JOIN(s1, s2) */ * FROM s1 INNER JOIN s2
ON s1.a_type=s2.a_type
WHERE a_date=‘20230421’ AND s2.a_flag=‘1’;
就没问题

消除warning
要么把子查询方式改写为join方式
要么在hint中使用正确的查询块限定(sel_1,sel_2之类+表别名)

换个客户端链接试试,之前碰到类似的原因是客户端把执行sql的注释干掉了

那搞不懂为什么加个索引就可以了


你原来有2个warnning,1是因为子查询,获取不到s2表名(这里可能tidb已经解决了子查询无法获取子查询汇总表名的hint异常,但是warnning信息未清除)
2是因为连接字段上没索引,无法走到INL_HASH_JOIN

感谢老师的回复,
第1点已经知道了
第二点,连接字段上没索引,我s2表上的a_type 字段就是1个主键索引不行?所以我的理解就是优化器在使用index hash join的时候,把s1表当成了内表,也就是说必须要求s1.a_type 有索引,没有的话,走不了index hash join
但是我用INL_HASH_JOIN(s2,s1),优化器还是会把s1当成是join的内表,所以有没有方式可以强行指定join的连接顺序?

纯粹的说方法的话,tidb是有类似oracle那样指定join顺序的:
方式1:leading(t1,t2,t3) 顺序按leading列表中的顺序进行join
方式2:straight_join() 顺序按from后表名出现的先后顺序进行join
但目前这些提示都有不少使用前提限制,还没细看。
例如手册上指出违反限制leading不启作用且会有warning警告的情形有:
不能有多个leading,
不能与straight_join()同时出现,
不能与任何xxx_join提示同时出现,
leading指定了重复的表名或不存在的表名,
优化器无法按照leading的顺序来连接。