我一般都是加hits来解决
用union代替or.用exists代替in
这不是只有TiDB才会有的问题,or在oracle里有索引合并的功能,IN数量过多也没办法,这是成本优化器的策略,强制走索引未必性能就一定好。
使用or条件的话,在mysql中如果不是两个条件都能用上索引的话最终也是会全表扫描的。
- 优化索引与查询 :确保
IN字段上有合适的单列索引。同时,考虑拆分大IN列表 为多个小批量(例如每次100个),或用临时表关联 替代大IN查询。 - 确保统计信息准确 :统计信息不准是优化器误判的常见原因。定期对相关表执行
ANALYZE TABLE,或适当增加IN字段的采样率。 - 使用优化器提示 :在确保索引有效且统计信息准确后,可尝试使用
USE_INDEX提示强制走索引。
有没有具体的语句
- 索引层面:为 OR 字段建联合索引、为 IN 字段建主键 / 唯一索引,开启索引合并;
- SQL / 执行计划层面:拆分大 IN 列表、用临时表 JOIN 替代 IN、强制使用索引;
- 全局控制层面:更新统计信息、调整成本模型参数、限制全表扫描行数 / 超时时间。
这些: SELECT * FROM bbc
WHERE bbc.biz_type=‘ER’
AND bbc.biz_no=‘930’
;
SELECT * FROM bbc
WHERE bbc.biz_type=‘ER’
AND bbc.bid BASIC_INFO_NO=‘930’
;
– 为什么是表扫描,而不是 index merge
SELECT * FROM bbc
WHERE
bbc.biz_type=‘ER’
AND
bbc.biz_no=‘930’
OR bbc.bid BASIC_INFO_NO=‘930’
)
表:bbc,记数率 44.6万
CREATE TABLE bbc (
id bigint NOT NULL AUTO_INCREMENT,
biz_type varchar(32) COLLATE utf8mb4_0900_ai_ci NOT NULL,
biz_no varchar(36) COLLATE utf8mb4_0900_ai_ci NOT NULL,
bid_basic_info_no varchar(50) COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_bid_change (bid_change_no),
KEY IX_biz_type_biz_no (biz_type,biz_no),
KEY IX_bid_no (bid_basic_info_no),
KEY IX_biz_no (biz_no),
KEY IX_biz_type_bid_basic_info_no (biz_type, bid_basic_info_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci AUTO_INCREMENT=592050 COMMENT=‘招标变更’
还是用索引吧,尽量索引覆盖
使用hint或者调整`tidb_opt_prefer_range_scan