我有以下查询
SELECT a.id, b.id from table1 AS a, table2 AS b
WHERE a.table2_id IS NULL
AND a.plane = SUBSTRING(b.imb, 1, 20)
AND (a.stat LIKE "f%" OR a.stat LIKE "F%")
以下是EXPLAIN的输出
+----+-------------+-------+------+-------------------------------------------------------------------------------------------+------------------------------+---------+------+----------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+-------------------------------------------------------------------------------------------+------------------------------+---------+------+----------+-------------+ | 1 | SIMPLE | b | ALL | NULL | NULL | NULL | NULL | 28578039 | | | 1 | SIMPLE | a | ref | index_on_plane,index_on_table2_id_id,mysql_confirmstat_on_stat | index_on_plane | 258 | func| 2 | Using where | +----+-------------+-------+------+-------------------------------------------------------------------------------------------+------------------------------+---------+------+----------+-------------+
查询需要 80分钟才能执行。
table1上的索引如下
+--------------+------------+--------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +--------------+------------+--------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | table1 | 0 | PRIMARY | 1 | id | A | 50319117 | NULL | NULL | | BTREE | | | | table1 | 1 | index_on_post | 1 | post | A | 7188445 | NULL | NULL | YES | BTREE | | | | table1 | 1 | index_on_plane | 1 | plane | A | 25159558 | NULL | NULL | YES | BTREE | | | | table1 | 1 | index_on_table2_id | 1 | table2_id | A | 25159558 | NULL | NULL | YES | BTREE | | | | table1 | 1 | index_on_stat | 1 | stat | A | 187 | NULL | NULL | YES | BTREE | | | +--------------+------------+--------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
和table2索引是。
+-------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | table2 | 0 | PRIMARY | 1 | id | A | 28578039 | NULL | NULL | | BTREE | | | | table2 | 1 | index_on_post | 1 | post | A | 28578039 | NULL | NULL | YES | BTREE | | | | table2 | 1 | index_on_ver | 1 | ver | A | 1371 | NULL | NULL | YES | BTREE | | | | table2 | 1 | index_on_imb | 1 | imb | A | 28578039 | NULL | NULL | YES | BTREE | | | +-------+------------+---------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
如何改进此查询的执行时间?
这是更新后的解释
EXPLAIN SELECT STRAIGHT_JOIN a.id, b.id from table1 AS a JOIN b AS b
ON a.plane=substring(b.imb,1,20)
WHERE a.table2_id IS NULL
AND (a.stat LIKE "f%" OR a.stat LIKE "F%");
+----+-------------+-------+------+-------------------------------------------------------------------------------------------+-------------------------------+---------+-------+----------+--------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+-------------------------------------------------------------------------------------------+-------------------------------+---------+-------+----------+--------------------------------+ | 1 | SIMPLE | a | ref | index_on_plane,index_on_table2_id,index_on_stat | index_on_table2_id | 5 | const | 500543 | Using where | | 1 | SIMPLE | b | ALL | NULL | NULL | NULL | NULL | 28578039 | Using where; Using join buffer | +----+-------------+-------+------+-------------------------------------------------------------------------------------------+-------------------------------+---------+-------+----------+--------------------------------+
答案 0 :(得分:1)
您的架构至少会以三种方式使您的查询失败。您将需要修改您的架构,以获得像这样的体面表现。我可以看到三种修复架构的方法。
第一种方式(可能非常容易修复):
a.stat LIKE "f%" OR a.stat LIKE "F%"
此OR
操作可能会使查询的运行时间翻倍。但是,如果您将stat
列的排序规则设置为不区分大小写,则可以将其更改为
a.stat LIKE "f%"
此列已有索引。
第二种方式(也许不是很难修复)。该条款明确地否定了索引的使用;当涉及NULL值时,它们是无用的。
WHERE a.table2_id IS NULL
您可以将table2_id
的定义更改为NOT NULL并提供默认值(可能为零)以指示缺少数据吗?如果是这样,您将处于良好状态,因为您将能够将其更改为使用索引的搜索谓词。
WHERE a.table2_id = 0
第三种方式(可能很难)。本条款中的函数的存在使得在加入时使用索引失败。
WHERE ... a.plane = SUBSTRING(b.imb, 1, 20)
你需要制作一个额外的专栏(是的,是的,在甲骨文中,它可能是一个功能索引,但谁拥有那种钱?)调用b.plane
或存储在其中的子字符串。
如果你做了所有这些事情并稍微重构一下你的查询,这就是它的样子:
SELECT a.id AS aid,
b.id AS bid
FROM table1 AS a
JOIN table2 AS b ON a.plane = b.plane /* the new column */
WHERE a.stat LIKE 'f%'
AND a.table2_id = 0
最后,您可以通过创建以下复合索引来覆盖查询的索引,从而略微调整此性能。如果您不确定这意味着什么,请查找覆盖索引。
table1 (table2_id, stat, plane, id)
table2 (plane, id) /* plane is your new column */
覆盖索引需要权衡:它们会降低插入和更新操作的速度,但会加快查询速度。只有你有足够的信息才能做出明智的权衡。
答案 1 :(得分:0)
必须对连接操作正在执行的列进行索引,并且MySQL优化器应该使用它来获得更好的性能。它将最小化检查的行数(连接大小)
试试这个
SELECT STRAIGHT_JOIN a.id, b.id from table1 AS a JOIN table2 AS b ON a.plane=substring(b.imb,1,20)
WHERE a.table2__id IS NULL and (a.stat LIKE "f%" OR a.stat LIKE "F%")
首先检查执行计划。如果它甚至没有使用index_on_imb
索引,请创建一个组合table2.imb
和table2.id
的复合索引,其中table2.imb
将按顺序排列。
答案 2 :(得分:0)
除了我对ID colmns的评论之外,您似乎正在尝试在“平面”而不是ID列上回填连接。如果我是正确的,你想要table2中table1中没有匹配的所有记录
select
a.id,
b.id
from
table2 b
left join table1 a
on b.id = a.table2_id
AND substr( b.imb, 1, 20 ) = a.plane
AND ( a.stat LIKE "f%"
OR a.stat LIKE "F%")
where
a.table2_id is null
另外,为了帮助索引加入,我会覆盖索引,这样引擎就不必回到原始数据来获取合格的记录。
table1 -- index ( plane, stat, table2_id, id )
table2 -- index ( imb, id )
但是,请再次澄清表连接的基础或者没有它基于一个键...根据table1的示例列有一个列table2_id,我认为这与table2.id有关。
执行左连接的目的基本上是说...对于左侧表中的每个记录(在我的示例table2中),无论条件/条件如何都加入到右侧表(table1) - 现在使用KEY ID列作为主要基础,然后使用平面和状态设置。
所以,即使我在table2_id上的两个表之间进行连接,如果它找到匹配项,它也将被排除......只有当它找不到匹配项时才会被包括在内。
最后,既然你隐藏了表格的真正基础,那么你就是在猜测那些帮助的工作。即使它是“个人”类型的数据,您也没有显示任何数据,我只是如何获得它。对于你想要获得的更好的心理形象比具有有限背景的虚假表/列名更好。
答案 3 :(得分:0)
派生表可能会提高性能,在这种情况下取决于索引index_on_table2_id,index_on_stat ..
SELECT a.id, b.id from table1 AS a, table2 AS b
WHERE a.table2_id IS NULL
AND a.plane = SUBSTRING(b.imb, 1, 20)
AND (a.stat LIKE "f%" OR a.stat LIKE "F%")
可以改写为.. 派生表将强制MySQL检查500543行,就像最后一个解释说的那样
SELECT a.id, b.id
FROM (SELECT plane FROM table1 WHERE (a.table2_id IS NULL) AND (a.stat LIKE "f%" OR a.stat LIKE "F%")) a
INNER JOIN table2 b
ON a.plane = SUBSTRING(b.imb, 1, 20)