SELECT COALESCE(tb2.number_new, tb1.number_original) as number
FROM
tb1
LEFT JOIN tb2 ON tb2.id = tb1.id
WHERE
tb1.number_original = <PARAM> OR tb2.number_new = <PARAM>
以上查询生成全表扫描。如何优化它?
说明:
+----+-------------+-------+-------+----------------+----------------+---------+------+----------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+----------------+----------------+---------+------+----------+----------------------------------------------------+
| 1 | SIMPLE | tb1 | index | number_original| number_original| 5 | NULL | 11683843 | Using index |
| 1 | SIMPLE | tb2 | ALL | PRIMARY | NULL | NULL | NULL | 2 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+-------+----------------+----------------+---------+------+----------+----------------------------------------------------+
我需要解决的问题是:
鉴于tb1
是一个包含字段number_original
的表,我想创建表tb2
来存储此字段的新值,(我称之为number_new
) 。我这样做是因为我无法改变number_original
值,我不喜欢在表number_new
上创建字段tb1
,因为它在95%+的11mi记录中都是NULL。
答案 0 :(得分:0)
您需要tb1.number_original
和tb2.number_new
的索引,也可能需要tb1.id
和tb2.id
的索引。然后你需要MySQL来利用你的索引。我不知道是否会。
通常,当没有索引回答查询的搜索参数时,DBMS将扫描表。
答案 1 :(得分:0)
这是您的查询:
SELECT COALESCE(tb2.number_new, tb1.number_original) as number
FROM tb1 LEFT JOIN
tb2
ON tb2.id = tb1.id
WHERE tb1.number_original = <PARAM> OR tb2.number_new = <PARAM>;
这是一个复杂的问题。首先,尝试两个索引tb1(number_original, id)
和tb2(number_new, id)
。
您可以将查询重写为:
SELECT COALESCE(tb2.number_new, tb1.number_original) as number
FROM tb1 LEFT JOIN
tb2
ON tb2.id = tb1.id
WHERE tb1.number_original = <PARAM>
UNION
SELECT COALESCE(tb2.number_new, tb1.number_original) as number
FROM tb1 LEFT JOIN
tb2
ON tb2.id = tb1.id
WHERE tb2.number_new = <PARAM>;
每个子查询都应使用其中一个索引。这确实会产生union
的开销(重复删除),但这可能比全表扫描更好。