【问题标题】:Unknown column in 'where clause'. Neste subquery to improve perfomance of 'ORDER BY'“where 子句”中的未知列。嵌套子查询以提高“ORDER BY”的性能
【发布时间】:2014-11-06 22:30:18
【问题描述】:

我的关系有点奇怪,但一定是这样:

SELECT COUNT(DISTINCT `t`.`id`) 
 FROM `radcliente` `t`
 LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao`
      ON (`endereco_instalacao`.`cliente_id`=`t`.`id`)
 LEFT OUTER JOIN `radcliente_telefone` `telefones`
      ON (`telefones`.`cliente_id`=`t`.`id`)
 LEFT OUTER JOIN `radcliente_email` `emails`
      ON (`emails`.`cliente_id`=`t`.`id`)
LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca`
      ON (`metodo_cobranca`.`cliente_id`=`t`.`id`) AND (metodo_cobranca.arquivo = 'nao')
LEFT OUTER JOIN `radacct` `ultimo_acct`
      ON (`ultimo_acct`.`username`=`t`.`login`) 
     AND (ultimo_acct.radacctid = (
         SELECT `radacctid` FROM
                  (SELECT radacctid
                     FROM `radacct` `fUzDDUDv` 
                    WHERE username = t.login
                  ) AS `fUzDDUDv` ORDER BY `radacctid` DESC LIMIT 1
                                  )
         )
WHERE (ultimo_acct.framedipaddress = '177.23.209.194')

“where 子句”中的未知列“t.login”。

更新:

是的,这可以解决问题。我创建了这个子查询,为什么我使用 Yii 框架,并且 has_one 关系没有限制,即如果一个“客户”有数百万个“账户”,框架会寻找所有“账户”,只取一个这给一些 GB 的流量,而且非常慢。为了解决,我使用子查询仅寻找最新的 id 来获取“客户”和最后一个“账户”并使其在 Active Record 中工作,直到那时一切都很好,但搜索速度很慢,寻找记录需要 40秒,然后我发现问题出在'ORDER BY'(radacctid是索引,表是innodb),因此我确实解决了子查询之外的'ORDER BY',然后解决了子查询列的问题表 'cliente' (t.login) 就像我上面解释的那样。

我也尝试过按另一个字段排序,例如“acctstarttime”,并且继续缓慢,只有当我这样做时才解决:

SELECT `radacctid` FROM
              (SELECT radacctid
                 FROM `radacct` `fUzDDUDv` 
                WHERE username = t.login
              ) AS `fUzDDUDv` ORDER BY `radacctid` DESC LIMIT 1

更新:

但是INNER JOIN的问题是如果'acct'没有结果就不会返回'cliente'。

更新

问题不在于t.login 的位置,但它不被识别为存在于子查询中,如果订单不慢,我无法“输出”。

更新

读我的cmets?这是这种情况。它真的只在生产服务器上一直有插入和更新。

【问题讨论】:

  • 很抱歉没有直接解决这个问题:我在您的陈述中看到一件事,我们在使用 ERP 数据库时遇到了很多问题。这涉及到主要的、最顶层的 SQL 语句的 WHERE 部分。您在 WHERE 子句中使用 (ultimo_acct.framedipaddress = '177.23.209.194')ultimo_acct 是一个表“左连接”到您的基本查询集 - 据我所知,这种比较将导致您的查询将 ultimo_acct 视为它在哪里 INNER-JOINED。
  • 据我所知,mysql 可能无法在您的原始子查询中识别t.login,因为它相对于t 表所在的顶级查询嵌套了一层太多。而不是(ultimo_acct.radacctid = (SELECT radacctid FROM (SELECT radacctid FROM radacct fUzDDUDv WHERE username = t.login) AS fUzDDUDv ORDER BY radacctid DESC LIMIT 1),使用(ultimo_acct.radacctid = (SELECT fUzDDUDv.radacctid FROM radacct fUzDDUDv WHERE fUzDDUDv.username = t.login ORDER BY fUzDDUDv.radacctid DESC LIMIT 1))就足够了,据我所知,通过这种修改mysql不应该给出错误
  • 是的,这行得通,但是'ORDER BY'太慢了。
  • 如果我理解得很好,(SELECT fUzDDUDv.radacctid FROM radacct fUzDDUDv WHERE fUzDDUDv.username = t.login ORDER BY fUzDDUDv.radacctid DESC LIMIT 1)) 部分会减慢整个查询的速度,你猜?
  • 绝对确定,但只有在与 WHERE 一起使用时才会减慢,例如,如果您只停留在 ORDER BY 'phpmyadmin' 中,并不慢(0.0007)并且仅在没有 ORDER BY 和 LIKE 的情况下使用 WHERE(0.0019) ,并记住 t.login fUzDDUDv .username 是索引。我相信这就是为什么查询结果的数量很大的原因似乎也很快,它在使用“排序”的“发送数据”处暂停。相信其他服务器在本地提供相同的东西更快,因为没有“查询”到所有 momendo the Freeradius。

标签: mysql nested subquery


【解决方案1】:

我希望这篇文章能以某种方式帮助你:

SELECT 
    COUNT(DISTINCT `t`.`id`) 
FROM 
    `radcliente` `t` 
    LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao` 
        ON (`endereco_instalacao`.`cliente_id`=`t`.`id`) 
    LEFT OUTER JOIN `radcliente_telefone` `telefones` 
        ON (`telefones`.`cliente_id`=`t`.`id`) 
    LEFT OUTER JOIN `radcliente_email` `emails` 
        ON (`emails`.`cliente_id`=`t`.`id`) 
    LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca` 
        ON (`metodo_cobranca`.`cliente_id`=`t`.`id`) 
            AND (metodo_cobranca.arquivo = 'nao') 
    INNER JOIN  
    (
     SELECT `ultimo_acct_INNER`.*
     FROM 
        `radacct` AS `ultimo_acct_INNER`
        INNER JOIN 
        (
         SELECT `fUzDDUDv`.`username` AS `maxID_username`, MAX(`radacctid`) AS `maxID_radacctid` 
         FROM  `radacct` `fUzDDUDv` 
         GROUP BY `fUzDDUDv`.`username`
        ) AS `radacct_MAX_ID` 
        ON `ultimo_acct_INNER`.`username`= `radacct_MAX_ID`.`maxID_username`
            AND `ultimo_acct_INNER`.`radacctid` = `radacct_MAX_ID`.`maxID_radacctid`
    ) AS `ultimo_acct`
    ON (`ultimo_acct`.`username`=`t`.`login`)                                  
WHERE 
    (ultimo_acct.framedipaddress = '177.23.209.194')

我替换了部分:

(...)
LEFT OUTER JOIN `radacct` `ultimo_acct`
      ON (`ultimo_acct`.`username`=`t`.`login`) 
     AND (ultimo_acct.radacctid = (
         SELECT `radacctid` FROM
                  (SELECT radacctid
                     FROM `radacct` `fUzDDUDv` 
                    WHERE username = t.login
                  ) AS `fUzDDUDv` ORDER BY `radacctid` DESC LIMIT 1
                                  )
         )
(...)

用这个:

    (...)
INNER JOIN  
        (
         SELECT `ultimo_acct_INNER`.*
         FROM 
            `radacct` AS `ultimo_acct_INNER`
            INNER JOIN 
            (
             SELECT `fUzDDUDv`.`username` AS `maxID_username`, MAX(`radacctid`) AS `maxID_radacctid` 
             FROM  `radacct` `fUzDDUDv` 
             GROUP BY `fUzDDUDv`.`username`
            ) AS `radacct_MAX_ID` 
            ON `ultimo_acct_INNER`.`username`= `radacct_MAX_ID`.`maxID_username`
                AND `ultimo_acct_INNER`.`radacctid` = `radacct_MAX_ID`.`maxID_radacctid`
        ) AS `ultimo_acct`
        ON (`ultimo_acct`.`username`=`t`.`login`)
(...)

【讨论】:

    【解决方案2】:

    您可以尝试以下修改(以优化性能)吗?

    SELECT COUNT(DISTINCT `t`.`id`) 
     FROM 
     (
        SELECT DISTINCT `t_sub`.`id`
        FROM
        `radcliente` `t_sub`
        LEFT OUTER JOIN `radacct` `ultimo_acct`
              ON (`ultimo_acct`.`username`=`t_sub`.`login`) 
             AND (ultimo_acct.radacctid = 
                          (SELECT `fUzDDUDv`.radacctid
                             FROM `radacct` `fUzDDUDv` 
                            WHERE `fUzDDUDv`.username = `t_sub`.login
                          ORDER BY `fUzDDUDv`.`radacctid` DESC LIMIT 1))
        WHERE (ultimo_acct.framedipaddress = '177.23.209.194')
     ) AS `t`
     LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao`
          ON (`endereco_instalacao`.`cliente_id`=`t`.`id`)
     LEFT OUTER JOIN `radcliente_telefone` `telefones`
          ON (`telefones`.`cliente_id`=`t`.`id`)
     LEFT OUTER JOIN `radcliente_email` `emails`
          ON (`emails`.`cliente_id`=`t`.`id`)
    LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca`
          ON (`metodo_cobranca`.`cliente_id`=`t`.`id`) AND (metodo_cobranca.arquivo = 'nao')
    

    它预先选择记录,首先将客户表连接到“大”表“radacct”,只选择不同的“正确”客户 id-s 集,然后将这个(相对)小集加入到最顶层的查询

    【讨论】:

    • 但默认 Yii 中没有。要利用 AR(我的应用程序所使用的所有功能),需要或多或少类似于我发布问题的查询。感谢您的帮助。
    【解决方案3】:

    我想我现在明白了。我没有使用 Yii 框架的经验,所以知道(考虑到您最后的评论)我想不出比以下更好的东西:

    SELECT COUNT(DISTINCT `t`.`id`) 
     FROM `radcliente` `t`
     LEFT OUTER JOIN `radcliente_endereco_instalacao` `endereco_instalacao`
          ON (`endereco_instalacao`.`cliente_id`=`t`.`id`)
     LEFT OUTER JOIN `radcliente_telefone` `telefones`
          ON (`telefones`.`cliente_id`=`t`.`id`)
     LEFT OUTER JOIN `radcliente_email` `emails`
          ON (`emails`.`cliente_id`=`t`.`id`)
    LEFT OUTER JOIN `radmetodo_cobranca` `metodo_cobranca`
          ON (`metodo_cobranca`.`cliente_id`=`t`.`id`) AND (metodo_cobranca.arquivo = 'nao')
    LEFT OUTER JOIN `radacct` `ultimo_acct`
              ON (`ultimo_acct`.`username`=`t`.`login`) 
             AND (ultimo_acct.radacctid = 
                          (SELECT `fUzDDUDv`.radacctid
                             FROM `radacct` `fUzDDUDv` 
                            WHERE `fUzDDUDv`.username = t.login
                          ORDER BY `fUzDDUDv`.`radacctid` DESC LIMIT 1))
    WHERE (ultimo_acct.framedipaddress = '177.23.209.194')
    

    我希望有人可以帮助您更准确地回答您的需求。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-13
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多