在第一个 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_original
和 tb2.number_new
的索引,可能还需要 tb1.id
和 tb2.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 扫描更好。
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_original
和 tb2.number_new
的索引,可能还需要 tb1.id
和 tb2.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 扫描更好。