大规模数据插入(bulk insert)是迁移、导入或填充大表时的常见任务。这种操作的效率取决于多个因素:
BULK INSERT或COPY(PostgreSQL)——它们的速度比普通的循环INSERT快。BULK INSERT my_table FROM 'C:\data\bulkdata.csv' WITH ( FIELDTERMINATOR = ',', ROWTERMINATOR = ' ', BATCHSIZE = 5000, TABLOCK );
TABLOCK可以减少大规模插入时的锁定冲突。
问题: 如果表参与事务,是否可以随时禁用和重新创建索引以加快bulk insert?
回答: 不可以,如果表参与活动事务,禁用或重新创建索引可能导致锁定、数据完整性问题或甚至数据丢失(如果事务回滚)。此操作应仅在不涉及事务时执行,或提前计划维护窗口。
-- 错误: BEGIN TRAN; ALTER INDEX ALL ON my_table DISABLE; -- ... bulk insert ... ALTER INDEX ALL ON my_table REBUILD; COMMIT;
在长事务中进行此类禁用是不可接受的!
故事1:在一个项目中,多个唯一索引的表中并行执行bulk insert导致频繁的死锁和性能急剧下降。解决方案是在导入期间暂时禁用非关键索引,并减少批处理操作的大小。
故事2:开发人员在数据加载期间忘记禁用外键约束,导致每次插入都检查其他大型表中相关记录的存在。这将加载时间从40分钟增加到9小时。禁用约束后,插入时间减少到12分钟。
故事3:尝试通过一个请求(未分批且未使用事务)插入大文件导致事务日志溢出(transaction log full)和数据库服务器崩溃。转向批处理后,问题得到解决。