如何使用执行块优化 Firebird 批量删除
How to optimize Firebird bulk delete with execute block
我的 Firebird table 有 6000 万行,我需要删除 ca。 table.
的一半
Table 行有汽车的 gps 位置、记录的时间戳和其他数据。 Table 有主键 IdVehicle+TimeStamp 和一个外键(进入 Vehicle table)。没有其他键或索引或触发器。一辆车有 100 000 - 500 000 条记录。
我需要删除旧数据,例如。从所有车辆中删除早于 2015 年 3 月 1 日的数据。我尝试了不同的方法,实际上使用我最快的 'execute block'
(使用主键)。首先,我阅读了 1.3.2015 之前的车辆记录。然后我将浏览各个记录并准备 sql 执行一个块,然后每 50 个条目将其执行到 firebird 中。
EXECUTE BLOCK AS BEGIN
DELETE FROM RIDE_POS WHERE IdVehicle = 1547 and date = '4.5.2015 8:56:47'
DELETE FROM RIDE_POS WHERE IdVehicle = 1547 and date = '4.5.2015 8:56:59'
DELETE FROM RIDE_POS WHERE IdVehicle = 1547 and date = '4.5.2015 8:57:17'
...... a total of 50 line
END
因此每800秒删除100万行(约1毫秒1条记录)。
还有没有更快捷的删除记录的方法?
此外,通过这种方式我只能删除几百万行,然后我必须重新启动 firebird,否则会开始变慢并卡住(在测试服务器上没有其他数据库/应用程序)。从早期的记录清除得很快,逐渐需要的时间越来越长。
对于定向,你在大 table 秒内常规擦除记录的速度有多快(不是完全擦除 table,而是只擦除一部分记录)。
如果你想删除 all 早于给定日期的记录,无论是什么车辆,那么在查询中包含 Idvehicle
是没有意义的,只是日期就足够了。即下面应该做的,直接查询,也不需要 execute block
:
DELETE FROM RIDE_POS WHERE date < '2015-03-01'
如果您必须删除数千(或数百万)条记录,请不要在单个事务中执行。您最好分几个步骤进行操作 - 例如删除 1000 条记录并提交,然后删除其他 1000 条记录并提交 - 它应该比在一个事务中删除一百万条记录要快。 1000 不是规则,这取决于您的具体情况(您的记录有多大,它们通过 "on delete cascade" 的外键有多少链接数据)。还要检查您是否有 "on delete" 触发器,也许可以暂时停用它们。
也许综合方法会有所帮助。
在以下日期添加(临时)索引:
CREATE INDEX IDX_RIDE_POS_date_ASC ON RIDE_POS (date)</pre>
写一个执行块:
EXECUTE BLOCK
AS
DECLARE VARIABLE V_ID_VEHICLE INTEGER;
BEGIN
FOR SELECT
DISTINCT ID_VEHICLE
FROM
RIDE_POS
INTO
:V_ID_VEHICLE
DO BEGIN
DELETE FROM RIDE_POS WHERE IdVehicle = :V_ID_VEHICLE AND date < '1.3.2015'
END
END
</pre>
如果您不想再拥有它,请删除它。
DROP INDEX IDX_RIDE_POS_date_ASC'</pre>
我认为即使考虑到创建索引所需的时间,您仍然可以节省一些删除记录的时间。
终于找到问题所在了。主要问题是我使用的是经典的 Winforms 应用程序(或 IBExpert),这会导致卡顿和减慢查询速度。我以前是执行block,擦除数据部分,解决了卡顿的问题,但是比较慢。
解决方案是创建一个简单的控制台应用程序并从中 运行 查询。 我保留主键并通过它擦除(不添加或删除索引)和删除记录的速度约为每毫秒 65 条(每 16 秒 100 万行)。
当我尝试删除主要数据并在日期时间列上添加索引时,擦除速度只提高了大约 5-10%。
我的 Firebird table 有 6000 万行,我需要删除 ca。 table.
的一半Table 行有汽车的 gps 位置、记录的时间戳和其他数据。 Table 有主键 IdVehicle+TimeStamp 和一个外键(进入 Vehicle table)。没有其他键或索引或触发器。一辆车有 100 000 - 500 000 条记录。
我需要删除旧数据,例如。从所有车辆中删除早于 2015 年 3 月 1 日的数据。我尝试了不同的方法,实际上使用我最快的 'execute block'
(使用主键)。首先,我阅读了 1.3.2015 之前的车辆记录。然后我将浏览各个记录并准备 sql 执行一个块,然后每 50 个条目将其执行到 firebird 中。
EXECUTE BLOCK AS BEGIN
DELETE FROM RIDE_POS WHERE IdVehicle = 1547 and date = '4.5.2015 8:56:47'
DELETE FROM RIDE_POS WHERE IdVehicle = 1547 and date = '4.5.2015 8:56:59'
DELETE FROM RIDE_POS WHERE IdVehicle = 1547 and date = '4.5.2015 8:57:17'
...... a total of 50 line
END
因此每800秒删除100万行(约1毫秒1条记录)。
还有没有更快捷的删除记录的方法?
此外,通过这种方式我只能删除几百万行,然后我必须重新启动 firebird,否则会开始变慢并卡住(在测试服务器上没有其他数据库/应用程序)。从早期的记录清除得很快,逐渐需要的时间越来越长。
对于定向,你在大 table 秒内常规擦除记录的速度有多快(不是完全擦除 table,而是只擦除一部分记录)。
如果你想删除 all 早于给定日期的记录,无论是什么车辆,那么在查询中包含 Idvehicle
是没有意义的,只是日期就足够了。即下面应该做的,直接查询,也不需要 execute block
:
DELETE FROM RIDE_POS WHERE date < '2015-03-01'
如果您必须删除数千(或数百万)条记录,请不要在单个事务中执行。您最好分几个步骤进行操作 - 例如删除 1000 条记录并提交,然后删除其他 1000 条记录并提交 - 它应该比在一个事务中删除一百万条记录要快。 1000 不是规则,这取决于您的具体情况(您的记录有多大,它们通过 "on delete cascade" 的外键有多少链接数据)。还要检查您是否有 "on delete" 触发器,也许可以暂时停用它们。
也许综合方法会有所帮助。
在以下日期添加(临时)索引:
CREATE INDEX IDX_RIDE_POS_date_ASC ON RIDE_POS (date)</pre>
写一个执行块:
EXECUTE BLOCK AS DECLARE VARIABLE V_ID_VEHICLE INTEGER; BEGIN FOR SELECT DISTINCT ID_VEHICLE FROM RIDE_POS INTO :V_ID_VEHICLE DO BEGIN DELETE FROM RIDE_POS WHERE IdVehicle = :V_ID_VEHICLE AND date < '1.3.2015' END END </pre>
如果您不想再拥有它,请删除它。
DROP INDEX IDX_RIDE_POS_date_ASC'</pre>
我认为即使考虑到创建索引所需的时间,您仍然可以节省一些删除记录的时间。
终于找到问题所在了。主要问题是我使用的是经典的 Winforms 应用程序(或 IBExpert),这会导致卡顿和减慢查询速度。我以前是执行block,擦除数据部分,解决了卡顿的问题,但是比较慢。
解决方案是创建一个简单的控制台应用程序并从中 运行 查询。 我保留主键并通过它擦除(不添加或删除索引)和删除记录的速度约为每毫秒 65 条(每 16 秒 100 万行)。
当我尝试删除主要数据并在日期时间列上添加索引时,擦除速度只提高了大约 5-10%。