【问题标题】:mysql left join statement running slowmysql left join 语句运行缓慢
【发布时间】:2012-12-23 21:04:25
【问题描述】:

使用左连接的 mysql 查询非常慢时遇到问题。

SELECT ip,T1.ipaddr,host,referrer,agent,page,url,thedate,DV,PV,notes
FROM visits_temp AS T1
LEFT JOIN (
    SELECT ipaddr,COUNT(DISTINCT LEFT(thedate,10)) AS DV
    FROM visits GROUP BY ipaddr
) AS T2 ON T1.ipaddr = T2.ipaddr
LEFT JOIN (
    SELECT ipaddr,notes
    FROM topvisitors
) As T3 ON T3.ipaddr = T1.ipaddr
LEFT JOIN (
    SELECT ipaddr,COUNT(ip) AS PV
    FROM visits
    GROUP BY ipaddr
) AS T4 ON T4.ipaddr = T1.ipaddr
WHERE referrer = '' AND
    thedate BETWEEN '2013-01-07 00:00:00' AND '2013-01-09 23:59:59'
GROUP BY T1.ip
ORDER BY thedate desc

这里的目标是获取网站的所有直接访问者流量,而不是 LEFT JOINS 进行查找以提供访问的总天数 (DV) 和查看的总页面数 (PV)。访问表目前有大约 290 万条记录,并且 ipaddr 和 thedate 字段已被索引。此查询需要近 90 秒才能完成。

SELECT ipaddr,COUNT(DISTINCT LEFT(thedate,10)) AS DV FROM visits GROUP BY ipaddr

SELECT ipaddr,COUNT(ip) AS PV FROM visits GROUP BY ipaddr

LEFT JOINS 中的各个 select 语句在自行运行时将在 0.03 秒内完成。在这种情况下,也许 LEFT JOIN 不是正确的方法,我愿意接受替代方案。

【问题讨论】:

  • 你试过EXPLAIN PLAN吗?它显示了什么?
  • 在日期范围内使用 between 时,我的大型表的性能非常糟糕。当使用这种结构时,mysql 会以某种方式拒绝索引。
  • @MarcB 使用Date >= LowerBownd and Date <=UpperBound 能解决问题吗?
  • 不。无论如何,就编译器/解析器而言,x between y and zx >=y and x<=z 相同。永远无法找到解决方法,最后只是对表进行了下注和分区。
  • ipaddr 和 thedate 字段的数据类型是什么?

标签: mysql performance optimization left-join


【解决方案1】:

这 4 个子查询可能会减慢速度。

这应该与您的查询相同,只是更快:

SELECT ip,T1.ipaddr,host,referrer,agent,page,url,thedate,DV,PV,notes
FROM visits_temp AS T1
LEFT JOIN (
    SELECT ipaddr, COUNT(DISTINCT LEFT(thedate,10)) AS DV, COUNT(ip) AS PV
    FROM visits
    GROUP BY ipaddr
) AS T2 ON T1.ipaddr = T2.ipaddr
LEFT JOIN topvisitors T3 ON T3.ipaddr = T1.ipaddr
WHERE referrer = '' AND
    thedate BETWEEN '2013-01-07 00:00:00' AND '2013-01-09 23:59:59'
GROUP BY T1.ip
ORDER BY thedate desc

如果保证T1 的每一行在T2T3 中都有匹配的行,则可以将LEFT JOIN 替换为JOIN,这应该允许优化器做更多的事情,这也可以加快速度(尽管有例外)。

我无法想象这会返回所需的结果,它将在 ipaddr 上分组,但随后只为每个 ip 返回这些分组中的(任何)1 个。 MySQL 不会阻止这一点。如果您详细说明您的要求(根据您使用的字段/表格),解决这个问题应该不会太难(尽管这在技术上可能属于不同的问题)。

【讨论】:

    【解决方案2】:

    您在 where 子句中使用了 referrer 和 thedate。在visits_temp 表中的这两个字段上创建复合索引可能会提高性能。

    确保您在 topvisitors 表中的 ipaddr 字段上也有索引。

    【讨论】:

      猜你喜欢
      • 2010-12-18
      • 1970-01-01
      • 1970-01-01
      • 2012-06-26
      • 1970-01-01
      • 2012-10-25
      • 2018-04-02
      • 1970-01-01
      • 2014-05-09
      相关资源
      最近更新 更多