问题描述
我需要删除一堆记录(字面意思是数百万),但由于性能问题,我不想在单个语句中进行删除。所以我创建了一个视图:
CREATE VIEW V1
AS
SELECT FirsT 500000 *
FROM TABLE
WHERE W_ID = 14
之后我做了一堆删除,例如:
DELETE FROM V1 WHERE TS < 2021-01-01
我想要的是在 While loop
和存储过程中导入此逻辑。我试过这样的 SELECT COUNT
查询:
SELECT COUNT(*)
FROM TABLE
WHERE W_ID = 14 AND TS < 2021-01-01;
我可以在与条件相同的过程中使用这个数字吗?我该如何管理?
这是我尝试过的,但出现错误
错误:动态 sql 错误; sql 错误代码 = -104;令牌未知;当
代码:
CREATE PROCEDURE DeleteBatch
AS
DECLARE VARIABLE CNT INT;
BEGIN
SELECT COUNT(*) FROM TABLE WHERE W_ID = 14 AND TS < 2021-01-01 INTO :cnt;
WHILE cnt > 0 do
BEGIN
IF (cnt > 0) THEN
DELETE FROM V1 WHERE TS < 2021-01-01;
END
ELSE break;
END
我就是无法理解这个。
澄清一下,在我的 previous question 中,我想知道如何在删除许多记录后管理 garbage_collection
,我做了建议 - SELECT * FROM TABLE;
或 gfix -sweep
和效果很好。 正如评论中提到的,正确的说法是 SELECT COUNT(*) FROM TABLE;
在那之后,另一个更大的数据库给了我 - 超过 5000 万。问题是数据库的运行速度非常慢。我设法找到了它所在的服务器,用 DELETE 语句杀死了它以清理数据库。
这就是我想尝试批量删除的原因。那里的减速问题纯粹是硬件 - HDD 不见了,我们更换了它。之后,执行语句和进行备份和恢复以回收磁盘空间都没有问题。
解决方法
假设您需要删除的数据,一旦存储过程启动就不需要回滚,还有另一种方法可以处理存储过程中的大量 DELETE。
示例存储过程将一次删除 500,000 行。它将循环直到没有更多行要删除。 AUTONOMOUS TRANSACTION 将允许您将每个删除语句放在其自己的事务中,并在语句完成后立即提交。这是在存储过程中发出隐式提交,而您通常无法这样做。
CREATE OR ALTER PROCEDURE DELETE_TABLEXYZ_ROWS
AS
DECLARE VARIABLE RC INTEGER;
BEGIN
RC = 9999;
WHILE (RC > 0) DO
BEGIN
IN AUTONOMOUS TRANSACTION DO
BEGIN
DELETE FROM TABLEXYZ ROWS 500000;
RC = ROW_COUNT;
END
END
SELECT COUNT(*)
FROM TABLEXYZ
INTO :RC;
END
,
因为性能问题
那些到底是什么?我不认为你实际上是在提高性能,只是在循环中运行 delete
但在同一事务中,或者甚至在相同的时间跨度内运行不同的 TX。你似乎在解决一些错误的问题。问题不在于您如何创建“垃圾”,而在于 Firebird 如何以及何时“收集”它。
例如,Interbase/Firebird 引擎中的 Select Count(*)
表示对所有表进行自然扫描,并且垃圾收集通常由它触发,如果大量垃圾被收集,它本身会变长创建(并且大规模删除肯定会,无论是由一百万行语句还是百万行语句完成)。
How to delete large data from Firebird SQL database
如果您真的想减慢删除速度 - 您必须全天候传播该活动,并使您的客户端应用程序例如每 15 分钟调用一次删除 SP。您将不得不向表中添加一些列,将其标记为删除,然后执行这样的工作
CREATE PROCEDURE DeleteBatch(CNT INT)
AS
DECLARE ROW_ID INTEGER;
BEGIN
FOR SELECT ID FROM TABLENAME WHERE MARKED_TO_DEL > 0 INTO :row_id
DO BEGIN
CNT = CNT - 1;
DELETE FROM TABLENAME WHERE ID = :ROW_ID;
IF (CNT <= 0) THEN LEAVE;
END
SELECT COUNT(1) FROM TABLENAME INTO :ROW_id; /* force GC now */
END
...并且每 15 分钟你做一次 EXECUTE PROCEDURE DeleteBatch(1000)
。
总的来说,这可能只会更慢,因为单行“精确定位” - 但至少它会分散延迟。
,使用 DELETE...ROWS。
How can I fork my own GitHub repository?
但正如我在上一个问题的回答中已经说过的那样,最好花时间调查减速的根源,而不是通过删除数据来解决它。