【问题标题】:How to truncate and add new rows to the table with a select query never getting empty results如何使用选择查询截断并将新行添加到表中,永远不会得到空结果
【发布时间】:2015-03-19 02:54:01
【问题描述】:

我有一个要求,其中一个表包含某些事物的状态。 该表被截断,并且每秒插入新的状态数据。 问题是,如果在删除和后续插入之间执行选择查询,用户将得到空表作为回报。 我认为 SQL 事务在这里无济于事,但不确定。 此外,如果选择查询在删除和插入查询之间执行,它不应该返回错误,因为它被数据库锁阻塞。它应该等到删除+插入操作完成。

实施这样一个系统的最佳方式是什么? 我应该如何形成“删除+插入”查询和“选择”查询?

提前谢谢你。

--------附加信息 该表将是多个繁重查询的结果,并且将每秒更新一次,这样应用程序就不会运行这些繁重的查询,而是从该表中获取所需的信息。 所以每秒截断并插入一次,然后随机选择多个。

【问题讨论】:

  • 为什么你认为交易在这里没有帮助?
  • 开始一个事务,截断,插入新行,最后提交。
  • 因为据我了解,可以在事务中的删除和插入之间读取数据。 transaction 将允许我将 sql 操作列表视为一个,以便能够恢复它,否则,其他查询可以根据我的理解读取脏数据。此外,它不应该使其他选择查询失败。我对交易的理解错了吗?
  • 喜丹和亚伦。我认为交易是最好的方式,就像你说的那样。我做了一些更多的测试,到目前为止它似乎运行良好。然而,我们将采用不同的方法,但我认为交易解决方案最适合我的需要。谢谢。

标签: sql sql-server sql-server-2005


【解决方案1】:

不要截断表格。相反,使用身份主键或日期作为主键插入新状态。然后做:

select top 1 date
from table
order by date desc

select max(date)
from table

(这些应该有基本相同的执行计划。)

然后,您插入新日期。插入完成后,数据立即可用。

然后您可以在闲暇时删除旧行。

【讨论】:

  • 我没有从表格中获取日期。我正在选择整个表。我说的是状态数据,您似乎将其误解为状态日期。
  • @user3754372 。 . .其实并不是。只需继续插入记录并使用datetime 列或标识列上的索引提取最后一条记录。您将不再有竞争条件,甚至不必开始搞乱事务。
  • 每秒发生一次(我修改了问题以帮助您更好地理解场景),如果我不截断,表会很大,即使我每次都删除旧行,我的主键也会是很大。你仍然认为它是最好的选择吗?我更想了解如何使用 sql 进行锁定以完成此任务。如果我找不到其他解决方案,你提到的是我的备用计划。
  • 我投票赞成 Gordon 的建议,只是使用时间戳作为主键。每天提早安排任务以删除前一天的条目。这样它就不会变得很大。您甚至可以创建一个仅公开最新条目(带有或不带有时间戳)的视图,这样您的开发人员就不必更改他们的查询(重命名表,创建具有相同名称的视图)。事实上,新行可以通过视图插入,因此您只需删除truncate 语句并创建日常任务。
【解决方案2】:

根据您的描述,此表始终只包含一行,即最后一次状态更改。内容大约每秒变化一次,显然是一天 24 小时。

与其通过一对截断/插入操作来更改数据,不如只更新一行?一次操作,没有竞争条件,完全没有锁定冲突。

甚至有一种方法可以在不更改任何现有代码的情况下做到这一点:

  • 重命名表
  • 创建一个显示重命名表中的行的视图。将其命名为原始表名。
  • 在视图上创建一个“代替插入”触发器。触发器对表执行更新而不是插入。这可以使用合并语句来执行,如果表碰巧为空,该语句将起作用。

哎呀,我错了。您仍然需要更改代码以删除 truncate 语句。它不会对视图起作用,但会引发异常。不幸的是,您不能使用触发器拦截截断并简单地忽略它。

然后当执行插入时,不再需要截断并且插入转换为更新(或合并)。一次操作。

【讨论】:

  • 它不只插入 1 行。我不知道我在哪里提到它插入一行,但如果我这样做了,那就不是这样了。它根据一天中的时间插入 0 到 500 行。
猜你喜欢
  • 2021-06-02
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 1970-01-01
  • 2018-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多