We are currently evaluating the use of MySQL partitions for a small application of ours. The application basically just sits at the end of a message queue and logs our API requests (that include a timestamp) to a database using Hibernate. Unfortunately we get a lot of requests and querying the database has become very slow.
What we would like to do is partition the table by timestamp (per month) since our regular query pattern is something like "get certain requests between time A and B". If A and B are in two consecutive months, which will mostly be true, then this would just hit two partitions.
As MySQL's range partitions have to be created manually I would like to add this maintenance task to our Java application where it can be done automatically. The idea is something like:
- Have a utility Thread that runs regularly (using
ScheduledExecutorService
or something) - In the thread, check if there is a partition for the next month
- If not, create it
That's all fine, but I'm stuck trying to get MySQL's partitioning info using Hibernate and create partitions. What's the best way to do this (I'm OK if this will be MySQL specific)?
- Is there a specific API in Hibernate to get MySQL partitioning info for a table, and also to create partitions?
- Should I use raw SQL (
SHOW CREATE TABLE ...
,ALTER TABLE ... ADD PARTITION
) and parse the output myself?
EDIT:
The table looks like this (I removed some columns not relevant to the question):
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
and the slow query is (generated by Doctrine apparently):
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
When EXPLAIN
ing the query MySQL says it's using the apikey_timestamp_rows_idx
index.
A little context: We want to know, for a given API key, how many requests with rows > 0
each user sent in a given period.
The table currently has about 2.2bn rows.