MySQL-在live server上执行密集查询
我在MySQL数据库中更新和插入数百万行时遇到了一些问题。我需要标记表A中的5000万行,将标记的5000万行中的一些数据插入表B,然后再次更新表A中的5000万行。表A中约有1.3亿行,表B中约有8000万行 这需要在实时服务器上进行,而不拒绝从网站访问其他查询。问题是,当此存储过程运行时,来自网站的其他查询最终被锁定,HTTP请求超时 以下是SP的要点,为了便于说明,有点简化:MySQL-在live server上执行密集查询,mysql,database,large-data,myisam,large-data-volumes,Mysql,Database,Large Data,Myisam,Large Data Volumes,我在MySQL数据库中更新和插入数百万行时遇到了一些问题。我需要标记表A中的5000万行,将标记的5000万行中的一些数据插入表B,然后再次更新表A中的5000万行。表A中约有1.3亿行,表B中约有8000万行 这需要在实时服务器上进行,而不拒绝从网站访问其他查询。问题是,当此存储过程运行时,来自网站的其他查询最终被锁定,HTTP请求超时 以下是SP的要点,为了便于说明,有点简化: CREATE DEFINER=`user`@`localhost` PROCEDURE `MyProcedure`
CREATE DEFINER=`user`@`localhost` PROCEDURE `MyProcedure`(
totalLimit int
)
BEGIN
SET @totalLimit = totalLimit;
/* Prepare new rows to be issued */
PREPARE STMT FROM 'UPDATE tableA SET `status` = "Being-Issued" WHERE `status` = "Available" LIMIT ?';
EXECUTE STMT USING @totalLimit;
/* Insert new rows for usage into tableB */
INSERT INTO tableB (/* my fields */)
SELECT /* some values from TableA */
FROM tableA
WHERE `status` = "Being-Issued";
/* Set rows as being issued */
UPDATE tableB SET `status` = 'Issued' WHERE `status` = 'Being-Issued';
END$$
DELIMITER ;
不管您在做什么,三次处理50万行都会很慢 确保您的更新正在影响较小的不相交集。并逐个执行,而不是在同一事务中执行 如果您已经这样做了,而MySQL行为不正常,请尝试对代码进行以下细微调整:
create a temporary table
begin
insert into tmp_table
select your stuff
limit ?
for update
do your update on A using tmp_table
commit
begin
do your insert on B using tmp_table
do your update on A using tmp_table
commit
这应该能将锁保持最短的时间。这怎么办?它基本上是在循环中调用原始存储过程,直到达到所需的总量,并且在调用之间有一个睡眠周期(如2秒),以允许其他查询进行处理
increment
是一次要做的量(本例中使用10000)totalLimit
是要处理的总金额sleepSec
是两次呼叫之间的休息时间
BEGIN
SET @x = 0;
REPEAT
SELECT SLEEP(sleepSec);
SET @x = @x + increment;
CALL OriginalProcedure( increment );
UNTIL @x >= totalLimit
END REPEAT;
END$$
显然,如果增量不能被平均整除,它可以使用一些数学来确保增量不会超过总限制,但它似乎是有效的(我所说的“有效”是指允许其他查询仍然从web请求中处理),而且总体上看起来也更快
有什么见解吗?这是个好主意吗?坏主意?这些表使用哪种数据库引擎?
状态也可以变成tinyint
或char(1)
。更新长字符字段的速度较慢。这些是MyISAM表,而状态字段实际上是一个枚举,有3个可能的值,可以将其分解为更小的进程。实际上,我创建了一个存储过程,在较小的卡盘中多次运行另一个存储过程,它的工作效果似乎要好得多(即:运行原始存储过程以处理10000个数据块,直到总共达到5000000个数据块)。它似乎成功地将锁保持在较短的时间内,并允许处理其他查询。“我实际上创建了一个存储过程,在较小的卡盘中多次运行另一个存储过程”--但这将在一个事务中运行整个过程,不是吗?(这正是我的观点…)嗯,这是有道理的。我主要关心的是把所有东西都锁起来,这样网站就不能使用数据库了。你能看看我发布的答案,让我知道你的想法吗?它似乎工作得很好,但你是对的…因为它仍然在一个存储过程中,它将在一个事务中,但它似乎没有保持低cks在表上(这对我很好)。非常感谢您的帮助!!坦率地说,我不确定MySQL将如何处理它。它可能会起作用。我只知道一个事实,当以这种方式处理时,Postgres将在一个事务中处理整件事情,并相应地锁定事情。(出于充分的理由,他们还没有实现存储过程,特别是异步事务。)