SQL Server中使用"WITH SCHEMABINDING"有哪些缺点?

64
我有一个数据库,其中有数百个命名不规范的表(例如CG001T,GH066L等),并且我针对每个表都有视图,这些视图都有“友好”的名称(例如视图“CUSTOMERS”是“SELECT * FROM GG120T”)。我想将“WITH SCHEMABINDING”添加到我的视图中,以便我可以享受与之相关的一些优势,例如能够对视图进行索引,因为一些视图具有计算列,在实时计算上比较耗费资源。 SCHEMABINDING这些视图有什么缺点吗?我找到了一些含糊其辞地提到缺点的文章,但从未详细说明。我知道一旦一个视图被捆绑,你就不能更改任何会影响该视图的内容(例如列数据类型或排序),除非先删除该视图,所以这是一个缺点,但除此之外呢?看起来,能够对视图本身进行索引的能力远远超过了需要仔细规划架构修改的缺点。

3
您不需要放弃这个视图,但您必须删除关联模式绑定并调整该视图。 - JeffO
10个回答

50

除非您先删除视图,否则无法更改/删除表。


4
在我看来,这是一个很大的问题,特别是当你想要修改数据库结构,但没有原始DDL语句时。在这些情况下,你需要尝试使用SCHEMABINDING生成完整的DDL语句来创建视图/函数,然后删除它们并重新创建它们。要仅仅更改一列的大小,就要进行相当大的任务。 - jpierson
22
无需删除视图本身,只需对其进行 ALTER 操作以使其不再绑定模式,然后再进行 ALTER 操作以恢复其绑定模式。 - Paul

35

完全没有。这样更安全,我们在各个方面都使用它。


8
如果没有不利因素,并且更安全(这是我的最初印象),那么为什么人们不会使用它呢?保护您的视图免受意外破坏似乎应该是一个优先考虑,或者说应该反过来——默认情况下是WITH,在需要时才声明WITHOUT。 - SqlRyan
2
懒惰,过度的纪律(例如合格的列等) - gbn
1
有没有办法将其设置为默认选项,还是它总是需要有意识地完成? - SqlRyan
3
大约一个月前,我遇到了这样的情况——我更改了底层表格,但视图返回的结果完全错乱了。原来视图中使用了"SELECT * FROM"语句,我不得不在刷新视图之前,让它意识到底层架构已经发生了变化 :) - SqlRyan
5
@Triynko说:这是有很好的原因的。任何需要影响整个索引视图的基本表更改都是不允许的。例如,对于仅更改的行计算SUM很容易。此外,我不认为盲目表重建是一个好主意:高级SQL和这种开发不相容。 - gbn
显示剩余3条评论

35

哦,使用SCHEMABINDING肯定有缺点 - 这是因为SCHEMABINDING,特别是与计算列一起使用时“锁定”关系,使得某些“琐碎的更改”几乎不可能。

  1. 创建一个表。
  2. 创建一个SCHEMABOUND UDF。
  3. 创建一个计算持久列引用该UDF。
  4. 在该列上添加索引。
  5. 尝试更新UDF。

祝你好运!

  1. 不能删除或更改UDF,因为它是SCHEMABOUND。
  2. 不能删除该列,因为它用于索引。
  3. 不能更改该列,因为它是计算列。

好吧,真糟糕。现在,像ApexSQL Diff这样的工具可以处理这个问题,但问题在于我甚至无法开始修改模式!

我并不反对SCHEMABINDING(在本例中需要UDF),但我反对没有找到一种“暂时禁用”SCHEMABINDING的方法


1
你的意思是创建一些循环SCHEMABOUND引用是可能的吗?除了使用不带SCHEMABINDING选项重新创建数据库之外还有其他方法可以解决这个问题吗?在你的情况下删除索引可以解除阻塞吗? - Guillaume86
3
  1. 由于它与模式绑定,因此无法删除或更改UDF。
  2. 不是这样的,模式绑定的作用与此相反。
  3. 由于该列为计算列,因此无法更改。您是什么意思?
- MarredCheese
  1. 由于其为SCHEMABOUND,因此无法删除或更改UDF。这与SCHEMABINDING无关,而是与您在计算列中使用UDF有关。
  2. 由于其为计算列,因此无法更改COLUMN。嗯,是的?这与SCHEMABINDING无关,而是与(MS)SQL的工作方式有关。
- Tom Lint
1
这个答案说,如果我创建了一个长的模式对象链,每个对象都依赖于前一个对象,我可能需要暂时改变或删除(而不仅仅是禁用)其中一些对象,顺序要与添加它们的相反顺序相同,以便可以在塔底进行模式更改。当然,这就是 OP 所说的“更加谨慎地规划自己的模式修改”的意思。但 UDF 示例仍然很有启发性。 - Jirka Hanika

7

唯一的缺点是,如果您将视图绑定到模式,则只能引用其他模式绑定视图。

我知道这一点,因为我尝试将视图绑定到模式,但出现了错误消息,告诉我它不能被绑定到模式,因为其中一个它所引用的其他视图没有绑定到模式。

唯一的后果是,如果您突然想要更新一个绑定到模式的视图以引用某个新视图或现有视图,则可能还需要将该新视图或现有视图绑定到模式。在这种情况下,您将无法更新视图,希望您的数据库开发人员知道如何处理绑定到模式的视图。


4
如果这些表是来自第三方应用程序(它们因试图隐藏其表而臭名昭著),则如果尝试修改任何这些表,可能会导致升级失败。你只需要在更新/升级之前修改没有模式绑定的视图,然后再将它们放回去即可。就像其他人所提到的一样,这需要一些规划、纪律等。

1
我想这是正确的,而且比在 DDL 期间删除视图要少侵入性得多。最近我不得不更改一些列的排序规则,只需执行 ALTER/更改排序规则/ALTER 就比删除视图并在我工作时破坏应用程序要容易得多。 - SqlRyan
1
不幸的是,仅通过 ALTER 语句删除 SCHEMABINDING 对于索引视图不起作用,因此在这些情况下,我认为唯一的解决方法仍然是删除并重新创建视图。 - jpierson
我刚刚测试了对我的索引视图进行 ALTER VIEW 操作,以查看会发生什么。我原本期望会看到某种类型的错误(这在 SQL Server 中是很常见的),但实际上它只是删除了我的索引。因此,在不知道是否存在索引的情况下,谨慎使用 ALTER 更改视图的模式绑定属性。 - jpierson
2
如果您删除了模式绑定(必须使用完全重建视图的alter),则无论如何都无法创建索引,因此是的,如果您重新添加模式绑定,则必须重新创建索引。 - JeffO

2
另一个缺点是您需要为所有内容使用模式限定名称:您将收到许多此类错误消息: “无法对视图'view'进行模式绑定,因为名称'table'对于模式绑定无效。名称必须采用两部分格式,并且对象不能引用自身。” 另外,“关闭”模式绑定也需要使用alter view,这要求您重新定义视图的select语句。我认为唯一不必重新定义的是任何授权。这让我很失望,因为覆盖视图似乎是一种本质上不安全的操作。 这有点像添加非空约束的方式,强制您重写列的数据类型-令人讨厌! 您还必须重新定义依赖于要更改的模式绑定对象的任何其他视图或过程...这意味着您可能必须重新定义(并可能破坏)大量级联函数和视图,以仅向一列添加非空约束。 就个人而言,我认为这并不真正代表解决方案,最好有一个良好的流程,使任何数据库更改都可以自动应用,这样更改数据库就不会成为一场噩梦。这样,当您对表进行更改时,可以将所有视图+函数从头开始删除并重新创建(它们在创建时会被检查),作为流程的一部分。

1

这对我来说似乎是一个缺点(#号是我的):

Cannot create index on view "###.dbo.###" because it uses a LEFT, RIGHT, or FULL OUTER join, and no OUTER joins are allowed in indexed views. Consider using an INNER join instead.

我需要我的左连接。这个Stack Overflow问题很相关。

1
使用 tSQLt 单元测试框架时,当使用 FakeTable 方法时,您可能会遇到问题并需要解决方案。这种方法无法伪造与模式绑定的视图链接的表。请注意,保留 HTML 标记。

1
自 SQL Svr 2005 以来,提到的负面影响几乎无法超越这个最佳实践。它避免了可怕的表格卷轴。对我来说一个主要的负面影响是,模式绑定的 sprocs、funcs 和 views 不能包括“外部”数据库,例如 master 数据库,因此,除非您的生产核心数据库位于 master 中,否则您可以将所有出色的实时系统内容丢进垃圾箱。对我来说,没有 sys 的东西我无法处理。当然,并非所有处理都需要无卷轴性能,并且快速和慢速结果可以同时在更高的数据类层中组合。

0

如果你的工具(如ssms等)不能很好/优雅地处理基础对象上的模式更改失败,那么你可能会引起一些真正的混乱。这就是我现在所面临的问题,我也意识到这是一个边缘案例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接