mysql - 缓慢的 MySQL 查询——JOIN 中的 CASE

标签 mysql query-optimization

<分区>

我有两个表:all_ufo (U) 和 rights (R)。参见 ERD: enter image description here

rights 是父表。 all_ufo 是 child 。

这是我的查询:

SELECT *
FROM all_ufo U
LEFT JOIN rights R
ON CASE
  WHEN U.UPC IN (
    SELECT DISTINCT UPC
    FROM rights
    WHERE UPC IS NOT NULL
    AND Channels IS NULL)
  THEN R.UPC 
    AND U.UPC = R.UPC

  WHEN U.Artist IN (
    SELECT DISTINCT Artist
    FROM rights
    WHERE Artist IS NOT NULL
    AND Channels IS NULL)
  THEN R.Artist
    AND U.Artist = R.Artist

  WHEN U.Label IN (
    SELECT DISTINCT Label
    FROM rights
    WHERE Label IS NOT NULL
    AND Channels IS NULL)
  THEN R.Label
    AND U.Label = R.Label
END
;

rights 表有点奇怪:它有 3 个级别的契约(Contract),我想将 all_ufo 中的每个行项目匹配到一个且只有一个契约(Contract)。

查询在 R 中为 U 中的每一行(有一行的地方)查找匹配项,从 UPC 开始,然后是 Artist,然后是 Label。

这是 R 表的示例。这里有一行代表表中的每一种条目(NULL 值在这里显示为字符串“NULL”,但在数据库中它们实际上是 null):

这是来自 U 的 20 条随机线的样本:

在我的示例数据(20 行)中,我得到了预期的结果。但是当我在整个表(大约 60 万行)上运行它时,它会运行一个小时左右然后终止。

我还尝试将 R 表分成三个单独的表,每个表对应一种类型的契约(Contract)。这是我试过的 MySQL 脚本,由于不正确的 SQL (?) 而失败了:

SELECT *
FROM all_ufo U
CASE
WHEN U.UPC IN (
SELECT DISTINCT UPC
FROM Contracts_Release
WHERE Channels IS NULL)
THEN LEFT JOIN Contracts_Release R
ON (U.UPC = R.UPC
AND R.ContractLevel = 'ReleaseLevel')

WHEN U.Artist IN (
SELECT DISTINCT Artist
FROM Contracts_Artist
WHERE Channels IS NULL)
THEN LEFT JOIN Contracts_Artist R
ON U.Artist = R.Artist
AND R.ContractLevel = 'ArtistLevel'

WHEN U.Label IN (
SELECT DISTINCT Label
FROM Contracts_Label
WHERE Channels IS NULL)
THEN LEFT JOIN Contracts_Label R
ON U.Label = R.Label
AND R.ContractLevel = 'LabelLevel'
END
;

我从来没有学过很多关于索引、数据库调优、查询优化等的知识。但是我已经尝试过这个没有任何键的查询,两个表都有主键,索引基于单个列,索引基于多列。我没有尝试让该查询“正确”运行。

谁能告诉我这里的最佳方法?我已经在研究和试错之间交替了大约 5 天......

最佳答案

确保您仅连接到 R 中的一行的更简单方法是向 R 添加一个主键列,并引用该主键。然后所有关于契约(Contract)级别的复杂逻辑都消失了。 U 中的一行只能引用 R 中的一行。

ALTER TABLE rights 
     ADD COLUMN rights_id INT AUTO_INCREMENT,
     ADD PRIMARY KEY (rights_id);
ALTER TABLE all_ufo ADD COLUMN rights_id INT;

将有关契约(Contract)级别的详细信息视为 R 中行的属性,而不是行的身份。也就是说,一旦你将 U 匹配到 R 中的正确行,你就可以找出它是什么级别的契约(Contract)。

SELECT ...
FROM all_ufo U
JOIN rights R ON U.rights_id = R.rights_id
WHERE R.Channels IS NULL;

P.S.:您的 SQL 中还有许多其他内容让人说“WTF?”例如:

    SQL 中的
  • CASE 只是一个表达式,您不能在每个 case 中嵌入 JOIN 子句和其他内容。它不像 C++ 中的 case 结构。在此处阅读有关 MySQL 的 IFCASE 的信息:https://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html#operator_case

  • 为什么几乎每一列都使用 TEXT 和 BIGINT?有充分的理由选择更适合每一列的数据类型。如果您对数据的了解不足以选择数据类型,那么您可能还没有充分考虑您的项目。

  • 数量是双倍的?这意味着您可以拥有一个不是整数值的数量?似乎不太可能。

  • USD.Payable 是 DOUBLE?由于舍入行为,您永远不应将 FLOAT 或 DOUBLE 用于货币。 If I had a dime for every time I've seen someone use FLOAT to store currency, I'd have $999.997634.

  • 避免使用带点的列名。 SQL 允许在名称中使用标点符号和特殊字符,但每次使用它们时都必须分隔列名。如果您使用 _ 而不是点,则不必分隔列名称。

关于mysql - 缓慢的 MySQL 查询——JOIN 中的 CASE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45944757/

相关文章:

mysql - 选择 COUNT 个值,按同一列分组,在另一列上不同

mysql - 如何查看MySQL全文索引的索引内容?

c# - fatal error 导致超时 -mysql

sql-server - 优化sql脚本占用CPU资源

mysql - 如何优化具有多个连接的查询?

mysql group by 查询的性能问题

php - 回显更新值而不是旧值

php - 检查值是否是结果集中第一次出现

c# - 用于存储加密字段数据的最佳数据类型

mysql - 优化从多个表中子选择数据的查询