【发布时间】:2015-10-14 13:23:10
【问题描述】:
我们目前正在评估我们的一个小型应用程序是否使用 MySQL 分区。该应用程序基本上只是位于消息队列的末尾,并使用 Hibernate 将我们的 API 请求(包括时间戳)记录到数据库中。不幸的是,我们收到了很多请求,查询数据库变得非常慢。
我们想做的是按时间戳(每月)对表进行分区,因为我们的常规查询模式类似于“在时间 A 和 B 之间获取某些请求”。如果 A 和 B 连续两个月,这在大多数情况下是正确的,那么这只会命中两个分区。
由于 MySQL 的范围分区必须手动创建,我想将此维护任务添加到我们的 Java 应用程序中,以便自动完成。这个想法是这样的:
- 拥有一个定期运行的实用线程(使用
ScheduledExecutorService或其他东西) - 在线程中,检查下个月是否有分区
- 如果没有,请创建它
没关系,但我一直在尝试使用 Hibernate 获取 MySQL 的分区信息并创建分区。最好的方法是什么(如果这将是 MySQL 特定的,我可以)?
- Hibernate 中是否有特定的 API 来获取表的 MySQL 分区信息以及创建分区?
- 我应该使用原始 SQL(
SHOW CREATE TABLE ...、ALTER TABLE ... ADD PARTITION)并自己解析输出吗?
编辑:
表格如下(我删除了一些与问题无关的列):
CREATE TABLE `request` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`apikey` varchar(32) NOT NULL,
`timestamp` datetime NOT NULL,
`rows` int(11) DEFAULT NULL,
`user_id` varchar(15) DEFAULT NULL
PRIMARY KEY (`id`),
KEY `apikey_idx` (`apikey`),
KEY `timestamp_idx` (`timestamp`),
KEY `apikey_timestamp_rows_idx` (`apikey`,`timestamp`,`rows`)
) ENGINE=InnoDB AUTO_INCREMENT=2190385211 DEFAULT CHARSET=utf8
慢查询是(显然是由 Doctrine 生成的):
SELECT
r0_.user_id AS user_id0, COUNT(r0_.id) AS sclr1
FROM
request r0_
WHERE
r0_.apikey = 'XXX' AND r0_.rows > 0 AND r0_.timestamp >= '2015-09-15 00:00:00' AND r0_.timestamp < '2015-10-15 00:00:00'
GROUP BY r0_.user_id
HAVING sclr1 > 0
ORDER BY sclr1 DESC
LIMIT 500
当EXPLAIN查询MySQL说它正在使用apikey_timestamp_rows_idx索引。
一点上下文:我们想知道,对于给定的 API 密钥,每个用户在给定的时间段内发送了多少 rows > 0 请求。
该表目前大约有 22 亿行。
【问题讨论】:
-
让我们看看实际的查询,并 SHOW CREATE TABLE。分区不一定比复合索引做得更好。
-
我将表架构和查询添加到我的问题中
标签: java mysql database hibernate partitioning