2015-10-14 35 views
4

我们目前正在评估MySQL分区对于我们的小应用程序的使用。应用程序基本上只是坐在消息队列的末尾,并使用Hibernate将我们的API请求(包括时间戳)记录到数据库中。不幸的是,我们收到很多请求,查询数据库变得非常缓慢。用Hibernate管理MySQL分区

我们想要做的是按时间戳(每月)对表格进行分区,因为我们的常规查询模式类似于“在时间A和B之间获得某些请求”。如果A和B连续两个月,这将主要是真实的,那么这将只是两个分区。

由于MySQL的范围分区必须手动创建,所以我想将这个维护任务添加到我们的Java应用程序中,它可以自动完成。我们的想法是这样的:

  1. 有定期执行的程序线程(使用ScheduledExecutorService或东西)
  2. 在线程,检查是否有下个月
  3. 如果不分区,创建

这一切都很好,但我坚持尝试使用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 

,并(通过主义显然产生)慢查询:

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 ing查询MySQL表示它使用apikey_timestamp_rows_idx索引。

稍微的上下文:我们想知道,对于给定的API密钥,每个用户在给定的时间段内发送的请求数量为rows > 0

该表目前约有22亿行。

+0

我们来看看实际的查询和SHOW CREATE TABLE。分区不一定会比组合索引做得更好。 –

+0

我在表格模式和查询中添加了我的问题 –

回答

0

我不知道任何处理表分区的hibernate API。

我想你别无选择,只能使用原生SQL。你可以在你的Java代码中使用SQL(正如我认为你所建议的那样),或者将它存储在一个存储过程中。

您可以使用Java或MySQL进行安排。如果您在应用程序服务器中使用线程来执行此操作,那么您的每个应用程序服务器都会有这样的计划作业。这使得很难控制工作实际执行的频率。在这种情况下这可能不是什么大问题,因为分区相关的查询不是很重。

您也可以在MySQL中安排它(请参阅How to schedule a MySQL query?)。该选项可以提供对作业(例如,DBA)的更多可见性,并且更易于管理和监视。

0

我没有看到该分区可以提供帮助。您必须扫描批次的行;这就是缓慢的。

KEY `apikey_idx` (`apikey`), 
KEY `apikey_timestamp_rows_idx` (`apikey`,`timestamp`,`rows`) 

第一个是不需要的,因为第二个。第一滴。 (这会加速插入。)

apikey闻起来像某种散列;是吗?它是十六进制的?你可以通过UNHEXing和将它存储到BINARY(16)(在使用apikey的所有表中)来节省大量磁盘空间。 (小 - >更少的I/O - >更快。)

假设该行不改变它们插入后...我会建立一个存储

  • 日期“汇总表” (从timestamp
  • rows> 0或不
  • apikey
  • COUNT(*)

从该汇总表中,相当于SELECT将运行更快

考虑为类似的其他查询构建(并增量维护)汇总表。

我建议Hibernate正在考虑存储和检索数据的最佳方式。

+0

查询汇总表当然速度非常快,但是构建汇总表需要花费很多时间,那么这里的收益是多少? 我对分区的想法是这样的:表格非常大,但包含了大量我们不关心(当前)的数据。因此,如果我们关心的所有数据都在一个或两个分区(最近两个月),那么相关索引,表格文件等将变得更小,因此更容易缓存等。这是不正确的? –

+0

一旦汇总表被初始化,_incrementally_增加它们。例如,在午夜,通过INSERT INTO摘要SELECT DATE(timestamp),apikey,rows> 0,COUNT(*)FROM Fact WHERE timestamp> = CURRENT_DATE() - INTERVAL 1 DAY和timestamp