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.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上的另一个索引

这 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 连接速度慢。任何加快速度的方法的主要内容,如果未能解决你的问题,请参考以下文章

解决iis+php+mysql访问速度慢的方法

MYSQL远程连接速度慢的解决方法

mysql 远程连接速度慢的解决方案

php+mssql 访问速度慢是啥原因?

如何提高电脑运行速度

mysql 远程连接速度慢的解决方案