【发布时间】:2017-09-20 21:43:43
【问题描述】:
我在对子查询执行自联接的查询时遇到了一些问题,它花费的时间比我想象的要多,而且我在理解原因时遇到了一些问题。
问题如下,所有者可以拥有物品,但某些物品可能会出现两次,属于不同的所有者,从每个所有者我们可能会得到关于物品的稍微不同的信息,或者某些字段可能为空。
这是我的数据库的一个简单版本,它不包含 FK,并且索引仅在 IdOwner、IdItem 和 IdCategry 出现时存在。
所有者:
+----------------+---------------+------+-----+
| Field | Type | Null | Key |
+----------------+---------------+------+-----+
| IdOwner | bigint(20) | NO | PRI |
| IdPlace | int(10) | NO | |
| SomeDate | datetime | YES | |
+----------------+---------------+------+-----+
项目:
+----------------+---------------+------+-----+
| Field | Type | Null | Key |
+----------------+---------------+------+-----+
| IdItem | bigint(20) | NO | PRI |
| IdOwner | bigint(20) | NO | MUL |
| IdCategory | int(10) | NO | |
| DupValue1 | varchar() | YES | |
.
.
.
| DupValueN | varchar() | YES | |
+----------------+---------------+------+-----+
国家:
+----------------+---------------+------+-----+
| Field | Type | Null | Key |
+----------------+---------------+------+-----+
| IdOwner | bigint(20) | NO | PRI |
| Country | Varchar() | NO | PRI |
+----------------+---------------+------+-----+
DupValues 1 到 N 是我发现当项目重复时最有可能相同的列。
这是我目前正在使用的查询的简化版本:
SELECT subquery1.IdItem, subquery2.IdItem FROM
(SELECT i1.IdCategory, i1.IdOwner, i1.IdItem, i1.DupValue1, o1.IdSite, o1.SomeDate, COUNTRY.country
FROM ITEMS i1
LEFT JOIN OWNER o1 ON o1.IdOwner=i1.IdOwner
LEFT JOIN COUNTRY ON i1.IdOwner=COUNTRY.IdOwner
WHERE i1.IdOwner>9000000)
as subquery1
INNER JOIN
(SELECT i2.IdCategory, i2.IdOwner, i2.IdItem, i2.DupValue1, o2.IdSite, o2.SomeDate, COUNTRY.country
FROM ITEMS i2
LEFT JOIN COUNTRY COUNTRY ON i2.IdOwner=COUNTRY.IdOwner
LEFT JOIN OWNER o2 ON o2.IdOwner=i2.IdOwner
WHERE i2.IdOwner>9000000)
as subquery2
ON subquery1.IdItem<subquery2.IdItem
AND subquery1.IdCategory=subquery2.IdCategory
AND subquery1.IdSite!=subquery2.IdSite AND subquery1.country=subquery2.country
AND DATE(subquery1.SomeDate)=DATE(subquery2.SomeDate)
AND (subquery1.DupValue1=subquery2.DupValue1 OR subquery1.DupValue1 IS NULL OR subquery2.DupValue1 IS NULL)
还有更多的 SupValue 都具有相同的格式。
WHERE 子句用于限制所有者的数量,因为我仍在测试查询,当 WHERE 子句到位时,它将所有者限制为约 700k 行,并且使用该行数,wuery 需要约 30 分钟过程。
当我在查询中使用解释时,我得到这个:
+------+-------------+---------+--------+----------------------------------------+-------------+---------+------------------------+-------+------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+--------+----------------------------------------+-------------+---------+------------------------+-------+------------------------------------+
| 1 | SIMPLE | i1 | range | PRIMARY,UnivocID,dg_owner,dg_category | UnivocID | 8 | NULL | 19056 | Using index condition |
| 1 | SIMPLE | o1 | eq_ref | PRIMARY | PRIMARY | 8 | i1.IdTender | 1 | |
| 1 | SIMPLE | country | ref | PRIMARY | PRIMARY | 8 | i1.IdTender | 1 | Using index |
| 1 | SIMPLE | i2 | ref | PRIMARY,UnivocID,dg_owner,dg_category | dg_category | 4 | i1.IdMolecule | 657 | Using index condition; Using where |
| 1 | SIMPLE | o2 | eq_ref | PRIMARY | PRIMARY | 8 | i2.IdTender | 1 | Using where |
| 1 | SIMPLE | country | ref | PRIMARY | PRIMARY | 8 | i2.IdTender | 1 | Using index |
+------+-------------+---------+--------+----------------------------------------+-------------+---------+------------------------+-------+------------------------------------+
MariaDB 版本:10.1
我的两个问题:
¿是subquery2 对subquery1 的每一行都执行,这就是导致执行时间如此长的原因,还是ON 子句的性质有问题?
¿查询可以改进吗,也许放弃 JOIN 以支持或其他运算符?
【问题讨论】:
-
您是否需要子查询,或者可以在没有子查询的情况下直接完成(如果您在完整查询中包含聚合函数,则可能需要子查询)。
-
@Kickstart 我需要子查询,因为我需要将 3 个表中的数据转换为 1,然后我需要对结果表进行操作以检测重复项,进行内部连接是我知道的唯一方法这样做。
-
可能的问题是您使用的是 LEFT OUTER JOIN,因此一些返回的字段可能是 NULL。并且 NULL 不等于 NULL(但您基于国家字段相等而加入)。如果影响您的子查询具有 LEFT OUTER JOINs 的开销,但结果会以一种方式处理,这意味着结果可能来自 INNER JOINs
-
@Kickstart 一个项目“总是”有一个所有者,一个所有者总是有一个国家,所以永远不应该有一个 NULL 国家,因为我知道可以为空的字段我使用最后一行查询。
-
在这种情况下切换到在子查询中使用 INNER JOIN。但这也应该意味着您不需要使用子查询。