如何在 3GB 表上优化 Mysql Select
Posted
技术标签:
【中文标题】如何在 3GB 表上优化 Mysql Select【英文标题】:How to optimize Mysql Select with count on 3GB table 【发布时间】:2019-03-12 14:10:40 【问题描述】:我有一个包含 37,000,000 行和 3gb 数据的表。
CREATE TABLE `stats_raw` (
`user_id` INT(11) NOT NULL,
`date` DATETIME(6) NOT NULL,
`ip` VARBINARY(16) NULL DEFAULT NULL,
INDEX `stats_raw_user_id_index` (`user_id`),
INDEX `stats_raw_date_index` (`date`),
INDEX `stats_raw_user_id_data_index` (`user_id`, `date`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
;
当我尝试执行以下查询时(由 laravel 生成,这就是为什么它看起来很奇怪):
select count(ip) as total, INET6_NTOA(ip) as ip
from `stats_raw`
where `user_id` = 1 and date(`date`) >= '2019-02-10'
group by `ip`
order by `total` desc
limit 10
返回结果大约需要 40 秒。
如何在 mysql 上进行优化?
【问题讨论】:
使用物化视图? 嗨@RedaMeskali 我第一次听说它,这很容易做到吗? 是的,您可以在这里阅读它们:fromdual.com/mysql-materialized-views。 【参考方案1】:首先,我将查询写成:
select count(ip) as total, INET6_NTOA(ip) as ip
from `stats_raw`
where `user_id` = 1 and `date` >= '2019-02-10'
group by `ip`
order by `total` desc
limit 10;
其次,您想要在stats_raw(user_id, date, ip)
上建立索引。
也就是说,目前尚不清楚正在处理多少数据。我认为没有办法绕过group by
和order by
的排序,所以如果你有大量数据,你可能无法加快这个查询,没有更多的英勇努力(例如维护汇总表使用触发器)。
【讨论】:
感谢 Gordon,我更新了总行数,我在写问题时添加了 xxx 占位符并忘记更新它。将检查您的建议并更新 根据您的建议,查询时间缩短到 15 秒,这是一个很大的改进。会等着看我是否得到任何其他答案并奖励你。再次感谢 只做COUNT(*)
,而不是COUNT(ip)
。
嗨@RickJames 试过了,但我看不出几秒钟的区别。谢谢【参考方案2】:
Gordon 对这个查询非常满意,所以我的回答假设您将使用他的查询。
您可以尝试的一个小改进是将date
列数据类型更改为DATE
,而不是DATETIME
(假设您实际上不需要时间部分。)
通过这样做,您可以减少storage on that column from 5 bytes (or 8, if using a version of MySQL older than 5.6) to 3,这将允许一次加载更多数据,从而减少一些开销。
当然,如果您需要时间部分做其他事情,那么这不是一个选择。
【讨论】:
好吧,然后为用户建议一个较小的INT
。并使其成为UNSIGNED
。并摆脱stats_raw_user_id_index
以上是关于如何在 3GB 表上优化 Mysql Select的主要内容,如果未能解决你的问题,请参考以下文章