【问题标题】:Performance: Double nested subquery unknown column性能:双重嵌套子查询未知列
【发布时间】:2019-10-13 18:23:02
【问题描述】:

如果我在第一个子查询中执行 COUNT()/AVG(),mysql 会处理表中的所有行,因此有必要使用另一个子查询从所有行中过滤。

例如,如果我有 3 行,但只有 1 行的 id 应该得到计数,mysql 会处理所有 3 行(根据 EXPLAIN)并在之后执行 where 子句。

如果我能够在双嵌套子查询中选择这一行并在外部调用计数,那么性能会好得多。

问题mysql不允许在二级子查询中使用外部值。

我的代码的简单示例:

SELECT 
    pr.id, pr.catid, ... 
    (
        SELECT COUNT(pra.id)
        FROM (
            SELECT id
            FROM productsrating 
            WHERE pr.id = productid
        ) pra
    ) as ratingcount,  
    ...
FROM 
(
    SELECT id, ...
    FROM products 
    WHERE active = 1

) pr

-> 未知列 pr.id

我也尝试在主选择中使用 COUNT,但不允许在子查询中包含多个值。

编辑:我在 productid 上有一个索引。

EDIT2 解决方案: 抱歉,第一个子查询运行良好,服务器问题导致了不良行为。

【问题讨论】:

  • pr.id = productid替换为id = productid
  • pr.id 是表 products 的 id,如果我使用 'id' 它会从表 productsrating 中获取 id
  • 不,它不能。 JOIN 怎么样?
  • 向我们展示您的表结构
  • @tcadidot0 如果我做一个简单的加入并调用 avg 或计算相同的结果,

标签: mysql


【解决方案1】:

您似乎想要一个活跃产品的评分计数。这是正确的吗?

所以;为什么简单的左连接不起作用? PRA 的计数应仅基于有效的产品;所以索引使用应该在这里工作。

我需要查看示例数据/预期结果来确定这里的总体目标。

SELECT PR.*, count(PRA.ID)
FROM products PR
LEFT JOIN productsRating PRA
 on PR.ID = PRA.ProductID
WHERE PR.Active = 1
GROUP BY PR.*

替换 PR.* 所需的所有字段

也许这...似乎是一件奇怪的事情,要在平均/计数完成之前过滤产品评级。

SELECT PR.*, count(PRA.ID)
FROM products PR
LEFT JOIN (SELECT * FROM productsRating PRI
           WHERE EXISTS (SELECT 1 
                         FROM Products P
                         WHERE active = 1 and PRI.ProductID = P.ID)) PRA
 on PR.ID = PRA.ProductID
WHERE PR.Active = 1
GROUP BY PR.*

【讨论】:

  • 之前我使用 join 来连接数据,但问题是 COUNT 和 AVG 使用所有行 productsRating 即使很难连接到产品的 ID。由于这个原因,我尝试在计数之前整理所有行。
  • 嗯...也许使用相关子查询来首先限制派生表。但这似乎是一件奇怪的事情。操作顺序表示应该首先发生连接,并且在应用 where 子句之后,计数/平均值应该基于该连接结果。我很惊讶计数/平均值不是首先由 Join 过滤并由 where 限制。如果那真的发生了,这听起来像是一个可能的 mySQL 错误。您最初尝试此操作时是否使用了左/内?
  • 我现在将在主帖中添加完整的查询。但是我会遇到与您的相关子查询相同的问题,即我无法在子查询中访问 pr.id。例如, max() 确实可以正常工作,只是 count() 和 avg 会出现问题。我添加了一行 productid 与产品的任何 id 都不匹配,这个也得到了处理。
  • 嗯,对不起,现在重启服务器后,看起来简单的子查询正在工作并且过滤正确,不知道发生了什么可能索引没有被捕获。
  • PR 未在相关子查询中使用。我两次引用了产品 (P) 和 PR),所以我每次的深度都不会超过 1 级。很高兴知道重新启动清除了一切;不知道为什么不好:(
【解决方案2】:

尝试使用不同的计数

SELECT 
    pr.id, pr.catid, ... 
    (
        SELECT COUNT(Distinct productsrating.id)
        FROM productsrating 
        WHERE pr.id = productid
    ) as ratingcount,  
    ...
FROM 
(
    SELECT id, ...
    FROM products 
    WHERE active = 1

) pr

【讨论】:

  • 不幸的是,所有行仍然得到处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-04
  • 1970-01-01
  • 2018-11-28
  • 2016-01-31
  • 2019-10-12
  • 2020-11-18
相关资源
最近更新 更多