在第一个 table 的字段或第二个 table 的字段中使用 WHERE 进行左连接

LEFT JOIN with WHERE in a first table's field OR second table's field

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>

以上查询生成完整的 table 扫描。如何优化?

解释:

+----+-------------+-------+-------+----------------+----------------+---------+------+----------+----------------------------------------------------+
| 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 的 table,我想创建 table tb2 来存储该字段的新值, (我称之为 number_new)。我这样做是因为我无法更改 number_original 值,而且我不喜欢在 table tb1 上创建字段 number_new 因为它在 95%+ 中为 NULL 11 英里的记录。

您需要 tb1.number_originaltb2.number_new 的索引,可能还需要 tb1.idtb2.id 的索引。然后你需要 MySQL 来利用你的索引。不知道会不会

通常,当没有索引回答查询的搜索参数时,DBMS 将扫描 table。

这是您的查询:

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 的开销(删除重复项),但这可能比完整的 table 扫描更好。