2015-10-14 71 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