MySQL慢慢加入。任何加速的方法

时间:2009-08-18 00:11:24

标签: php mysql date join

我有2张桌子。 1是音乐,2是listenTrack。 listenTrack跟踪每首歌曲的独特播放。我试图获得本月流行歌曲的结果。我得到了我的结果,但他们只是花了太长时间。下面是我的表格和查询

430,000行

CREATE TABLE `listentrack` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `sessionId` varchar(50) NOT NULL,
    `url` varchar(50) NOT NULL,
    `date_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `ip` varchar(150) NOT NULL,
    `user_id` int(11) DEFAULT NULL,
     PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=731306 DEFAULT CHARSET=utf8

12500行

CREATE TABLE `music` (
   `music_id` int(11) NOT NULL AUTO_INCREMENT,
   `user_id` int(11) NOT NULL,
   `title` varchar(50) DEFAULT NULL,
   `artist` varchar(50) DEFAULT NULL,
   `description` varchar(255) DEFAULT NULL,
   `genre` int(4) DEFAULT NULL,
   `file` varchar(255) NOT NULL,
   `url` varchar(50) NOT NULL,
   `allow_download` int(2) NOT NULL DEFAULT '1',
   `plays` bigint(20) NOT NULL,
   `downloads` bigint(20) NOT NULL,
   `faved` bigint(20) NOT NULL,
   `dateadded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
   PRIMARY KEY (`music_id`)
) ENGINE=MyISAM AUTO_INCREMENT=15146 DEFAULT CHARSET=utf8


SELECT COUNT(listenTrack.url) AS total, listenTrack.url 
FROM listenTrack
LEFT JOIN music ON music.url = listenTrack.url
WHERE DATEDIFF(DATE(date_created),'2009-08-15') = 0
GROUP BY listenTrack.url
ORDER BY total DESC
LIMIT 0,10

这个查询不是很复杂,行不是太大,我不认为。

有没有办法加快速度?或者你能提出更好的解决方案吗?这将是每个月开始时的一项重要工作,但我也想做一天的结果。

哦,顺便说一句,我在本地跑步,超过4分钟跑步,但是生产需要大约45秒

9 个答案:

答案 0 :(得分:12)

我更像是一个SQL Server人,但这些概念应该适用。

我要添加索引:

  1. 在ListenTrack上,使用url和date_created
  2. 添加索引
  3. 在音乐上,使用网址
  4. 添加索引

    这些索引应该极大地提高了查询速度(我最初将表名混淆了 - 在最新的编辑中修复了。)

答案 1 :(得分:6)

在大多数情况下,您还应该索引JOIN中使用的任何列。在您的情况下,您应该同时为listentrack.urlmusic.url

编制索引

@jeff s - 索引music.date_created没有帮助,因为你首先通过一个函数运行它,所以MySQL不能在该列上使用索引。通常,您可以重写查询,以便静态使用索引引用列,如:

DATEDIFF(DATE(date_created),'2009-08-15') = 0

变为

date_created >= '2009-08-15' and date_created < '2009-08-15'

这将过滤掉2009-08-15中的记录,并允许该列上的任何索引成为候选者。请注意,MySQL可能不会使用该索引,它取决于其他因素。

最好的办法是在listentrack(url, date_created)上制作双重索引 然后是music.url

上的另一个索引

这两个索引将涵盖此特定查询。

请注意,如果在此查询上运行EXPLAIN,您仍然会获得using filesort,因为它必须将记录写入磁盘上的临时表以执行ORDER BY。

一般情况下,您应始终在EXPLAIN下运行查询,以了解MySQL将如何执行查询,然后从那里开始。请参阅EXPLAIN文档:

http://dev.mysql.com/doc/refman/5.0/en/using-explain.html

答案 2 :(得分:4)

尝试创建有助于加入的索引:

CREATE INDEX idx_url ON music (url);

答案 3 :(得分:3)

我想我可能已经错过了之前的明显。你为什么要加入音乐桌?您似乎根本没有使用该表中的数据,并且您正在执行不需要的左连接,对吧?我认为这个表在查询中会使它慢得多,不会添加任何值。将所有音乐引用输出,除非需要包含url,在这种情况下,您需要一个正确的连接以强制它不包含没有匹配值的行。


我会像其他人提到的那样添加新索引。具体来说,我会补充: 音乐网址 listentrack date_created,url

这将改善你的加入。

然后我会查看查询,你强迫系统在表的每一行上执行工作。将日期限制重新定义为范围会更好。

不确定我头脑中的语法: '2009-08-15 00:00:00'&lt; = date_created&lt; 2009-08-16 00:00:00

这应该允许它快速使用索引来定位适当的记录。音乐的两个关键索引应该允许它根据日期和URL查找记录。你应该试验一下,他们可能会更好地走向另一个方向url,date_created在索引上。

此查询的解释计划应在右侧列中为两者说“使用索引”。这意味着它不必点击表中的数据来计算您的总和。

我还会检查您为MySQL配置的内存设置。听起来你没有足够的内存分配。对基于服务器的设置和基于线程的设置之间的差异要非常小心。具有10MB缓存的服务器非常小,具有10MB缓存的线程可以快速使用大量内存。

雅各

答案 4 :(得分:2)

使用MySQL / MyISAM预先分组然后加入可以更快地完成任务。 (我很怀疑其他数据库需要这个)

这应该与非连接版本一样快:

SELECT
   total, a.url, title
FROM
(
  SELECT COUNT(*) as total, url
  from listenTrack
  WHERE DATEDIFF(DATE(date_created),'2009-08-15') = 0
  GROUP BY url
  ORDER BY total DESC
  LIMIT 0,10
) as a
LEFT JOIN music ON music.url = a.url
;

P.S。 - 使用id而不是url在两个表之间进行映射是合理的建议。

答案 5 :(得分:1)

为什么要在两个表中重复网址?

让listentrack改为持有music_id,并加入其中。删除文本搜索以及额外索引。

此外,它可以说是更正确的。您正在跟踪收听特定曲目的时间,而不是网址。如果网址发生变化怎么办?

答案 6 :(得分:0)

添加索引之后,您可能希望探索将date_created的新列添加为unix_timestamp,这将使数学运算更快。

我不确定为什么你有diff功能,因为看起来你正在寻找在特定日期更新的所有行。

您可能希望查看查询,因为它似乎有错误。

如果使用单元测试,则可以使用unix时间戳来比较查询结果和查询结果。

答案 7 :(得分:0)

您可能希望在两个表的url字段中添加索引。

说过,当我从mysql转换到sql server 2008时,使用相同的查询和相同的数据库结构,查询运行速度提高了1-3个数量级。

我认为其中一些与rdbms有关(mysql优化器不太好......),其中一些可能与rdbms如何保留系统资源有关。但是,比较是在只生成数据库的生产系统上进行的。

答案 8 :(得分:0)

以下内容可能有助于加快查询速度。

CREATE INDEX music_url_index ON music(url)使用BTREE; CREATE INDEX listenTrack_url_index ON listenTrack(url)使用BTREE;

您确实需要知道正在进行的比较和行扫描的总数。要获得该答案,请使用说明http://www.siteconsortium.com/h/p1.php?id=mysql002查看此处的代码,了解如何执行此操作。