我有两张表testa& TESTB。
CREATE TABLE `testa` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `testb` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT NULL,
`aid1` INT(10) DEFAULT NULL,
`aid2` INT(10) DEFAULT NULL,
`aid3` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`)
);
目前我在查询下面运行,以检索testa表中的id与tableb中的aid1,aid2,aid3的任何列匹配的所有行。查询正在检索精确结果,但执行时间最短为30秒,这太过分了。我也尝试使用UNION优化我的查询,但没有这样做。
SELECT a.id, a.name, b.name, b.id
FROM testb b
INNER JOIN testa a ON b.aid1 = a.id OR b.aid2 = a.id OR b.aid3 = a.id ;
如何优化查询,使其总执行时间在2-3秒内?
提前致谢...
EXPLAIN的结果:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE b ALL idx_aid1,idx_aid2,idx_aid3 (NULL) (NULL) (NULL) 10940
1 SIMPLE a ALL PRIMARY (NULL) (NULL) (NULL) 7512 Using where; Using join buffer
答案 0 :(得分:4)
因为你允许aid1,aid2,aid3为NULL(显然,根据你的解释,它们大多数是NULL),你的连接条件实际上是不可索引的。
为什么呢? SQL表达式b.aid1 = a.id OR b.aid2 = a.id OR b.aid3 = a.id
如果任何aid1,aid2或aid3为NULL,则求值为NULL,这就是MySQL计划程序不使用索引显示的原因。
解决方案:不要对aid1,aid2,aid3使用NULL。相反,发明特殊的id(比如说0),它确保在testa中不存在。 然后,确保testb.aid [123]为非NULL(并将其分配给0之前为NULL)。
编辑:为此问题添加替代方法。
如果您可以通过添加一个表来更改架构,也可以解决此问题。这个新表将包含您当前存储在表testb中的辅助列表,而testb将只包含一个链接到新表的id。这应该与此answer中解释的类似。这样做的另一个好处是你可以允许任意数量的援助(不仅仅是你现在的3个)。
答案 1 :(得分:1)
除了其他人建议的索引之外,请确保ANALYZE
表格,以便表格的统计信息是最新的。如果统计信息与表中的实际情况大不相同,那么查询规划器将做出错误的选择。
答案 2 :(得分:0)
您应该对以下列进行索引以避免全面扫描
`aid1` INT(10) DEFAULT NULL,
`aid2` INT(10) DEFAULT NULL,
`aid3` INT(10) DEFAULT NULL,
如果你想改变表格
ALTER TABLE testb ADD INDEX (aid1);
ALTER TABLE testb ADD INDEX (aid2);
ALTER TABLE testb ADD INDEX (aid3);
答案 3 :(得分:0)
您是否尝试加入IN
而不是OR
?
SELECT a.id, a.name, b.name, b.id
FROM testb b
INNER JOIN testa a ON a.id IN (b.aid1, b.aid2, b.aid3) ;