【问题标题】:LEFT JOIN with WHERE in a first table's field OR second table's field在第一个表的字段或第二个表的字段中使用 WHERE 左连接
【发布时间】:2015-08-11 11:13:21
【问题描述】:
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 的值,而且我不喜欢在表 tb1 上创建字段 number_new,因为在 95% 以上的 11mi 记录中它将为 NULL。

【问题讨论】:

  • 我不确定这是否有帮助,但是...摆脱 or 使用与 select WHERE COALESCE(tb2.number_new, tb1.number_original) = &lt;PARAM&gt; 相同的语句可能更有效...但是...如果填充了 new_number,它将永远不会搜索 original_number....所以结果会有所不同...
  • WHERECOALESCE 没有区别,全表扫描... :(
  • 您有矛盾,请修正。首先你SELECT来自tb2;那么你“想要创建 tb2”。它是哪一个?如果你正在做一个CREATE TABLE,让我们看看它和INSERT

标签: mysql sql database performance database-design


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    这是您的查询:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-12
      • 2017-09-05
      • 2014-05-23
      • 1970-01-01
      • 2020-08-08
      相关资源
      最近更新 更多