MySQL 连接速度慢。任何加快速度的方法
Posted
技术标签:
【中文标题】MySQL 连接速度慢。任何加快速度的方法【英文标题】:MySQL Slow on join. Any way to speed up 【发布时间】:2010-11-20 10:34:07 【问题描述】:我有 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
这个查询不是很复杂,行也不是太大,我不认为。
有什么办法可以加快速度吗?或者您能提出更好的解决方案吗?这将是每个月开始时的一项 cron 工作,但我也想按天完成。
哦,顺便说一句,我在本地运行,运行时间超过 4 分钟,但在 prod 上大约需要 45 秒
【问题讨论】:
【参考方案1】:我更喜欢 SQL Server,但这些概念应该适用。
我会添加索引:
-
在 ListenTrack 上,添加带有 url 和 date_created 的索引
在音乐上,添加带有 url 的索引
这些索引应该会极大地加快查询速度(我最初将表名混淆了 - 在最新的编辑中已修复)。
【讨论】:
我相信索引表名被翻转了。我也是第一次做到这一点,并在发布之前就抓住了它。 TheJacobTaylor 是对的,我把表名倒过来了。我已经解决了这个问题。 我的问题是,为什么我们都把它们弄反了?我再次浏览了帖子,但没有看到我遵循错误的触发器。 我的猜测是:在问题介绍中,它们被介绍为音乐然后是listentrack,但创建查询首先显示listentrack。【参考方案2】:在大多数情况下,您还应该索引 JOIN 中使用的任何列。在您的情况下,您应该同时索引 listentrack.url
和 music.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
上的另一个索引
这 2 个索引将涵盖此特定查询。
请注意,如果您在此查询上运行EXPLAIN
,您仍然会得到using filesort
,因为它必须将记录写入磁盘上的临时表才能执行 ORDER BY。
一般而言,您应该始终在EXPLAIN
下运行您的查询,以了解 MySQL 将如何执行查询,然后从那里开始。请参阅EXPLAIN
文档:
http://dev.mysql.com/doc/refman/5.0/en/using-explain.html
【讨论】:
残酷的时机。 :) 很好的答案。秒杀我。 非常感谢听起来很有用。我将按照您的链接阅读并尝试您的示例【参考方案3】:尝试创建一个有助于连接的索引:
CREATE INDEX idx_url ON music (url);
【讨论】:
【参考方案4】:我想我之前可能错过了显而易见的事情。你为什么要加入音乐桌?您似乎根本没有使用该表中的数据,并且您正在执行不需要的左连接,对吗?我认为这个表在查询中会使它变慢并且不会增加任何价值。删除所有对音乐的引用,除非需要包含 url,在这种情况下,您需要一个右连接来强制它不包含没有匹配值的行。
我会添加新的索引,就像其他人提到的那样。具体来说,我会补充: 音乐网址 听音日期_创建,网址
这将大大改善您的加入。
然后我会查看查询,您正在强制系统对表的每一行执行工作。最好将日期限制重新表述为一个范围。
不确定我脑海中的语法: 其中'2009-08-15 00:00:00'
这应该允许它快速使用索引来定位适当的记录。音乐上组合的两个关键索引应该允许它根据日期和 URL 找到记录。你应该尝试一下,他们可能会更好地去另一个方向 url,date_created 在索引上。
此查询的解释计划应在右侧列中显示“使用索引”。这意味着它不必点击表中的数据来计算总和。
我还会检查您为 MySQL 配置的内存设置。听起来您没有分配足够的内存。非常小心基于服务器的设置和基于线程的设置之间的差异。 10MB缓存的服务器很小,一个10MB缓存的线程可以很快使用大量内存。
雅各布
【讨论】:
我正在使用该表中的数据,但我正在调试缓慢的来源。没有加入 1 秒查询。在 music.url 上添加 idx 索引后加入,运行时间为 7 秒,添加 music.plays 将其推高到 10 您能否发布“真实”查询或带有索引的查询的解释计划?我们一天要讨论多少条记录(数量级)?你在盒子上使用了多少内存?索引和数据缓存,或者只是缓存在 InnoDB 上,非常重要且易于修复。【参考方案5】:使用 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
;
附: - 使用 id 而不是 url 在两个表之间进行映射是合理的建议。
【讨论】:
【参考方案6】:为什么要在两个表中重复 url?
让listentrack 持有一个music_id,然后加入它。摆脱文本搜索以及额外的索引。
此外,可以说它更正确。您正在跟踪特定曲目的收听时间,而不是 url。 url变了怎么办?
【讨论】:
【参考方案7】:添加索引后,您可能想探索为 date_created 添加一个新列作为 unix_timestamp,这将使数学运算更快。
我不确定为什么你有 diff 功能,因为看起来你正在寻找在特定日期更新的所有行。
您可能需要查看您的查询,因为它似乎有错误。
如果您使用单元测试,那么您可以将查询结果与使用 unix 时间戳的查询进行比较。
【讨论】:
【参考方案8】:您可能希望为两个表的 url 字段添加索引。
话虽如此,当我从 mysql 转换到 sql server 2008 时,使用相同的查询和相同的数据库结构,查询的运行速度提高了 1-3 个数量级。
我认为其中一些与 rdbms 有关(mysql 优化器不太好......),其中一些可能与 rdbms 如何保留系统资源有关。不过,比较是在只有 db 可以运行的生产系统上进行的。
【讨论】:
【参考方案9】:以下内容可能会加快查询速度。
使用 BTREE 在音乐(网址)上创建索引 music_url_index; CREATE INDEX listenTrack_url_index ON listenTrack (url) USING BTREE;
您确实需要知道正在发生的比较和行扫描的总数。要获得该答案,请查看此处的代码,了解如何使用说明 http://www.siteconsortium.com/h/p1.php?id=mysql002。
【讨论】:
以上是关于MySQL 连接速度慢。任何加快速度的方法的主要内容,如果未能解决你的问题,请参考以下文章