【问题标题】:Merge with Unique filtered index与唯一过滤索引合并
【发布时间】:2013-10-31 05:46:40
【问题描述】:

所以我今天发现了一个奇怪的 SQL Server 行为。

假设我有一个这样的表,id是主键

╔════╦══════╦════════╗
║ id ║ name ║ active ║
╠════╬══════╬════════╣
║  1 ║ a    ║      0 ║
║  2 ║ a    ║      1 ║
╚════╩══════╩════════╝

假设我有一个filtered unique index on name where active = 1。 现在,我只想为行切换为活动状态,将第一行设置为非活动状态,并将第二行设置为活动状态。当我尝试像这样更新它时

update Table1 set 
    active = n.active
from Table1 as t
inner join (values (1, 1), (2, 0)) as n(id, active) on n.id = t.id

工作正常。但如果我尝试合并:

merge Table1 as t
using (values (1, 1), (2, 0)) as n(id, active) on n.id = t.id
when matched then
    update set active = n.active;

如果失败并出现错误Cannot insert duplicate key row in object 'dbo.Table1' with unique index 'ix_Table1'. The duplicate key value is (a)

更奇怪的是,如果我有这样的表(第一行有活动 = 1,第二行有活动 = 0):

╔════╦══════╦════════╗
║ id ║ name ║ active ║
╠════╬══════╬════════╣
║  1 ║ a    ║      1 ║
║  2 ║ a    ║      0 ║
╚════╩══════╩════════╝

并像这样合并它:

merge Table1 as t
using (values (1, 0), (2, 1)) as n(id, active) on n.id = t.id
when matched then
    update set active = n.active;

它再次工作正常。所以看起来合并确实逐行更新并在每一行之后检查索引。我检查了唯一约束,没有过滤器的唯一索引,一切正常。只有当我合并合并和过滤索引时它才会失败。

所以问题是 - 这是一个错误吗?如果是,最好的解决方法是什么?

您可以在 sql fiddle demo 上试用。

【问题讨论】:

    标签: sql sql-server merge sql-server-2008-r2 filtered-index


    【解决方案1】:

    我在 sqlblog.com 上找到了这篇文章 - MERGE Bug with Filtered Indexes,由 Paul White 撰写,日期为 2012 年。

    他给出了几个解决方法:

    • 将过滤索引的 WHERE 子句中引用的所有列添加到索引键(INCLUDE 不够);或
    • 执行设置了跟踪标志 8790 的查询,例如选项(查询跟踪 8790)。

    经过一番研究,我发现如果我将主键列添加到更新中,它可以正常工作,因此查询变为:

    merge Table1 as t
    using (values (1, 1), (2, 0)) as n(id, active) on n.id = t.id
    when matched then
        update set active = n.active, id = n.id;
    

    我认为也可以从更新的索引中添加列,但尚未测试。

    sql fiddle demo

    【讨论】:

      猜你喜欢
      • 2012-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-29
      • 2011-03-18
      • 2017-02-19
      相关资源
      最近更新 更多