目前我正在测试TokuDB,我印象非常深刻。此时,每秒插入数量达到峰值,刚好超过每秒50,000次,同时运行了两个同步工作。平均插入率为每秒38.000至42.000次插入。
我想更高,每秒100,000次插入,因为我现在需要插入12亿个计算行,在不久的将来需要大约60亿个。我想就如何实现这一点提出一些建议: - )
我目前的设置:
My.cnf设置:
# TokuDB #
tokudb_cache_size = 2G
tokudb_commit_sync = 0
tokudb_fsync_log_period = 1000
TokuDB表格布局:
CREATE TABLE `t1` (
`id` int(15) NOT NULL AUTO_INCREMENT,
`m_id` int(11) NOT NULL,
`c1` decimal(6,2) DEFAULT NULL,
`c2` decimal(6,2) DEFAULT NULL,
`c3` decimal(6,2) DEFAULT NULL,
`c4` decimal(6,2) DEFAULT NULL,
`c5` decimal(6,2) DEFAULT NULL,
`c6` decimal(6,2) DEFAULT NULL,
`c7` decimal(6,2) DEFAULT NULL,
`factor` decimal(4,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=TokuDB DEFAULT CHARSET=latin1
CREATE TABLE `t2` (
`id` int(15) NOT NULL AUTO_INCREMENT,
`v_id` int(15) NOT NULL,
`pid` int(11) DEFAULT NULL,
`amount` decimal(6,2) DEFAULT NULL,
`unit` int(1) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=TokuDB DEFAULT CHARSET=latin1
我知道我没有使用任何其他索引 主键索引。这是由于密钥对时间的负面影响 有插入。将在该处创建每个表的群集密钥 插入作业结束。
其他MySQL命令行选项:
SET unique_checks=OFF;
不知怎的,我无法在my.cnf中得到这个...如果有人会知道怎么会非常感激(目前unique_checks = off会因为我的未知变量而阻止MySQL启动.CNF)。
SQL语句按批次分组为15.000。 PHP脚本生成SQL语句并通过mysqli_multiquery将查询发送到MySQL服务器:
<?PHP
foreach (generateCombinations($Arr) as $c) {
$QueryBatch[] = "insert into t1 values (NULL"
. ", " . $record->id
. ", " . rand(1, 35)
. ", " . rand(1, 140)
. ", " . rand(1, 20)
. ", NULL"
. ", " . rand(1, 14)
. ", " . rand(1, 300)
. ", " . rand(1, 4)
. ", NULL );";
$QueryBatch[] = "SET @t1id = LAST_INSERT_ID();";
$cntBatch++;
$pquery = array();
foreach ( $c as $key => $pid){
if ( is_null($pid) )
continue;
$pquery[] = "(NULL, @t1id, " . $pid . ", " . rand(1, 800) . ", 0)";
$cntBatch++;
}
$QueryBatch[] = "insert into t2 values " . implode(',', $pquery) . ";";
if ($cntBatch > 15000) {
$query = implode($QueryBatch);
if ( $mysqli->multi_query($query) ){
while ($mysqli->next_result()) {;}
} else {
printf("Errormessage: %s\n", $mysqli->error);
echo $query . "\n";
}
$cntBatch = 0;
unset($QueryBatch);
}
}
?>
SQL insert语句的示例:
insert into t1 values (NULL, 1 , 30, 100, 15, NULL, 10, 250, 2, NULL );
SET @t1id = LAST_INSERT_ID();
insert into t2 values (NULL, @t1id, 1, 750, 0),(NULL, @t1id, 1, 600, 0),(NULL, @t1id, 1, 500, 0),(NULL, @t1id, 1, 400, 0),(NULL, @t1id, 1, 300, 0),(NULL, @t1id, 1, 200, 0),(NULL, @t1id, 1, 100, 0);
insert into t1 values (NULL, 2 , 25, 95, 14, NULL, 11, 200, 3, NULL );
SET @t1id = LAST_INSERT_ID();
insert into t2 values (NULL, @t1id, 1, 600, 0),(NULL, @t1id, 1, 100, 0),(NULL, @t1id, 1, 300, 0),(NULL, @t1id, 1, 443, 0),(NULL, @t1id, 1, 521, 0),(NULL, @t1id, 1, 213, 0),(NULL, @t1id, 1, 433, 0);
[.. At least 14982 more..]
答案 0 :(得分:2)
如果是我,我会减少正在执行的语句数量,并减少提交次数。我假设AUTO_COMMIT已启用,因为我们没有看到任何BEGIN TRANSACTION
或COMMIT
语句。
这是一大堆个人INSERT
和SET
陈述。至少子表的插入使用多行插入,而不是每行的单独插入语句。
如果我需要这么快,我会
id
表生成t1
值,并在INSERT语句中包含这些值LAST_INSERT_ID()
t1
使用多行插入(而不是为每行分隔INSERT语句)BEGIN TRANSACTION
和COMMIT
t1
(序列化)以避免潜在的锁定争用如果是InnoDB,我也会SET FOREIGN_KEY_CHECKS=0
。
在代码中已经有大量的rand
函数调用;所以增加id
的整数t1
并不会移动指针。当我们开始时,我们需要一个查询来获取当前的AUTO_INCREMENT值,或者获取MAX(id),无论哪个......
基本上,我减少了正在执行的语句数量,并且每个语句完成了更多工作,并且在每个COMMIT
之前完成了更多工作。
每个语句插入十(10)t1
行显着减少需要执行的语句数。
BEGIN TRANSACTION;
-- insert ten rows into t1
INSERT INTO t1 (id,m_id,c1,c2,c3,c4,c5,c6,c7,factor) VALUES
(444055501, 1 , 30, 100, 15, NULL, 10, 250, 2, NULL )
,(444055502, 2 , 25, 95, 14, NULL, 11, 200, 3, NULL )
, ...
,(444055510, 10 , 7, 45, 12, NULL, 10, 300, 4, NULL )
;
-- batch together the t2 rows associated with the ten t1 rows we just inserted
INSERT INTO t2 VALUES
-- 444055501
(NULL, 444055501, 1, 750, 0)
,(NULL, 444055501, 1, 600, 0)
,(NULL, 444055501, 1, 500, 0)
,(NULL, 444055501, 1, 400, 0)
,(NULL, 444055501, 1, 300, 0)
,(NULL, 444055501, 1, 200, 0)
,(NULL, 444055501, 1, 100, 0)
-- 444055502
,(NULL, 444055502, 1, 600, 0)
,(NULL, 444055502, 1, 100, 0)
,(NULL, 444055502, 1, 300, 0)
,(NULL, 444055502, 1, 443, 0)
,(NULL, 444055502, 1, 521, 0)
,(NULL, 444055502, 1, 213, 0)
,(NULL, 444055502, 1, 433, 0)
-- 444055503
, ...
;
-- another ten rows into t1
INSERT INTO t1 (id,m_id,c1,c2,c3,c4,c5,c6,c7,factor) VALUES
(444055511, 11 , 27, 94, 15, NULL, 10, 250, 11, NULL )
,(444055512, 12 , 24, 93, 14, NULL, 11, 200, 12, NULL )
, ...
,(444055520, 10 , 7, 45, 12, NULL, 10, 300, 4, NULL )
;
INSERT INTO t2 VALUES
(NULL, 444055511, 1, 820, 0)
,(NULL, 444055511, 1, 480, 0)
, ...
;
-- repeat INSERTs into t1 and t2, and after 1000 loops
-- i.e. 10,000 t1 rows, do a commit
COMMIT;
BEGIN TRANSACTION;
INSERT INTO t1 ...
LOAD DATA INFILE
如果没有提及LOAD DATA INFILE
,任何关于插入性能的讨论都是不完整的。
为了获得最佳性能,无法击败。但是,由于我们没有将数据存储在文件中,并且我们没有关键值(t2
中的外键需要,而且我们已经获得了所有调用rand的权限要生成数据,LOAD DATA INFILE
似乎不太适合。