如何正确截断ETL管道中的登台表?

问题描述 投票:1回答:2

我们有一个ETL管道,该管道为上传到存储帐户(Azure)中的每个CSV运行。它在CSV上运行一些转换,并将输出也作为CSV写入另一个位置,并在数据库(SQL Azure)上调用存储过程,该存储过程将生成的CSV吸收(批量插入)到临时表中。

此管道可以并发执行,因为多个资源可以将文件上载到存储。因此,登台表经常插入数据。

然后,我们有一个计划的SQL作业(弹性作业),该作业会触发一个SP,该SP将数据从登台表移到最终表中。在这一点上,我们希望截断/清空临时表,以便在下一次执行作业时不重新插入它们。

问题是,我们无法确定从临时表到最终表的加载与truncate命令之间,没有任何新数据写入到临时表中而没有先插入到最终表中就可能被截断表格。

在将数据复制到最终表时,是否有一种锁定登台表的方法,以便试图写入该表的SP(从ETL管道调用)将只等到释放锁之后?通过使用事务或某些手动锁定命令可以实现吗?

如果没有,处理此问题的最佳方法是什么?

sql-server locking azure-sql-database etl staging-table
2个回答
1
投票

我喜欢sp_getapplock并在少数地方亲自使用此方法,因为它具有灵活性,您可以完全控制锁定逻辑和等待时间。

我看到的唯一问题是,在您的情况下,并发进程并不完全相等。

您有SP1,它将数据从登台表移到主表中。您的系统永远不会尝试运行此SP的多个实例。

将数据插入到临时表中的另一个SP2 can可以同时运行多次,这样做很好。

很容易实现锁定,以防止同时运行SP1或SP2的任何组合。换句话说,如果SP1和SP2的锁定逻辑相同,并且将它们视为相等,则很容易。但是,那么您将无法同时运行多个SP2实例。

[实现锁以防止同时运行SP1和SP2,同时允许SP2的多个实例同时运行,这并不明显。


[还有另一种方法不会尝试阻止SP的并发运行,而是接受并期望可以同时运行。

一种方法是将sp_getapplock列添加到登台表。或自动填充的日期时间(如果可以保证它是唯一的且永不减少),这可能会很棘手。或IDENTITY列。

SP2中将数据插入到临时表中的逻辑不变。

SP1中将数据从登台表移到主表中的逻辑需要使用这些标识值。

首先,从登台表中读取当前的身份最大值,并将其记住在变量中,例如rowversion。该SP1中登台表中的所有后续SELECT,UPDATE和DELETE应包括过滤器rowversion

这将确保如果在运行SP1时碰巧将新行添加到登台表中,那么该行将不会被处理,并且将保留在登台表中,直到下一次运行SP1。

此方法的缺点是您不能使用@MaxID,需要将WHERE ID <= @MaxIDTRUNCATE一起使用。


如果您可以让多个SP2实例互相等待(和SP1),则可以使用DELETE,类似于以下内容。我的存储过程中有此代码。您应该将此逻辑同时放入SP1和SP2。

我在这里没有明确地调用WHERE ID <= @MaxID,因为锁所有者设置为Transaction,并且引擎将在事务结束时自动释放锁。

您不必在存储过程中放入重试逻辑,它可以在运行这些存储过程的外部代码中。无论如何,您的代码都应该可以重试。

sp_getapplock

此代码保证在任何给定时刻只有一个过程正在与登台表一起使用。没有并发。所有其他实例将等待。

很明显,如果您尝试不通过这些SP1或SP2(首先尝试获取锁)访问登台表,则不会阻止这种访问。


0
投票

在将数据复制到最终表时,是否有一种锁定登台表的方法,以便试图写入该表的SP(从ETL管道调用)将只等到锁定被释放?通过使用事务或某些手动锁定命令可以实现吗?

看起来您正在寻找一种比事务级别更广泛的机制。 SQL Server / Azure SQL DB有一个,它称为应用程序锁定

sp_releaseapplock

在应用程序资源上设置锁定。

放置在资源上的锁与当前事务或当前会话相关联。当事务提交或回滚时,释放与当前事务相关联的锁。与会话相关联的锁在注销会话时释放。当服务器由于任何原因关闭时,所有锁都将释放。

可以使用sp_releaseapplock显式释放锁。当应用程序为相同的锁资源多次调用sp_getapplock时,必须将sp_releaseapplock调用相同的次数才能释放该锁。当使用事务锁所有者打开锁时,将在提交或回滚事务时释放该锁。

这基本上意味着您的ETL工具应打开与数据库的单个会话,获取锁定并在完成后释放。在尝试执行任何操作之前,其他会话应尝试获取该锁(由于已被使用而无法获取),等到它释放后才能继续工作。

© www.soinside.com 2019 - 2024. All rights reserved.