2

据我了解,SQL 视图代表“虚拟表”,其中数据实际上保存在视图引用的其他“后备表”中。可以将索引添加到视图以提高性能,但是如果视图只是一个虚拟表,这些索引实际上引用了什么?(它是后备表上的主键还是什么?)

想象一个由SELECT * FROM bookings WHERE IsDeleted=0表示的视图,带有一个关于bookings.AppointmentDate的索引 ...索引可能按约会日期排序(以便于搜索),并且每个索引叶保存该数据所在的行号在视图中......这会起作用......直到预订发生变化并且一些已删除的预订现在未被删除,建议的索引将保持未对齐。

另一种方法是让索引视图现在实际上是预订表的“分身”,因此它是物化的而不是虚拟的。现在索引可以引用分身拥有的任何主键,因此当预订被取消删除时不会中断。但同样,如果预订表发生变化,这个分身器必须“发现”它应该具有的新行(如未删除的预订)以及在返回结果之前需要从自身中删除的行,这在餐桌上不会很昂贵更新否定了使用索引视图的可能好处?

我试图了解索引视图是如何在幕后工作的。

4

4 回答 4

2

在 SQL Server 中,索引视图是已物化为聚集索引的视图,作为另一个副本。这通常对性能更好。

请注意,与定期刷新物化视图的 Oracle 不同, SQL Server 维护视图的索引以及对基表的任何修改。这是在同一个语句中完成的,其方式与正常的非聚集索引更新类似。它不像触发器,它在单独的范围内执行,它直接提供主查询计划。

它可能会拖累 DML 性能,例如更新和插入,但是它可以显着提高查询性能,尤其是对于大型聚合查询。请注意,聚合只存储最终的聚合结果。

为了提高性能,有很多限制,主要是防止服务器不得不查找其他行。所以你不能做一个LEFTorFULL连接,或者使用聚合结构,比如MAXor HAVING,这就是你需要COUNT_BIG聚合的原因。

于 2021-11-02T14:47:40.663 回答
1

虚拟表只是可以像表一样查询的任何东西,但实际上不是表。这在互联网上的许多地方都有错误的解释,因此看起来“虚拟表”与“视图”是同义词,但这是一种误导。从技术上讲,任何可以在查询中代替表的东西都是虚拟表,包括:

  • 观看次数(常规)
  • 索引/物化视图
  • 表值函数(常规)
  • 内联表值函数
  • 表变量

但它包括更多短暂的东西,例如:

  • 子查询表达式
  • CTE(公用表表达式)

以及特定于 DBMS 的内容,例如:

  • OpenQuery 表达式
  • 等等等等。

所以关于上面列表的重要一点是我列出了两次视图,“常规”类型的视图和“索引”视图。这是因为尽管它们看起来很相似,但实际上它们的实现方式完全不同。

在几乎所有 DBMS中,常规视图只是子查询表达式的命名别名。因此,当您定义一个名为MyViewsome的视图SELECT...,然后像这样使用该视图时:

SELECT * FROM MyView

解析器只是将视图名称替换为该视图的 SELECT 语句作为子查询:

SELECT * FROM (SELECT...) AS MyView

就是这样,这就是常规视图的全部内容(这就是为什么认为视图导致性能不佳的说法如此荒谬的原因,这不是它是视图的事实,而是子查询的使用不当)。

然而,索引视图是一个非常不同的东西。首先,它们的更老和更通用的术语是(来自 Oracle 和其他)物化视图。SQL Server 只是将它们称为索引视图,因为这就是您如何将常规视图转换为 SQL Server 上的物化视图的方式:向其添加索引。

与常规视图不同,索引/物化视图实际上是 SQL 初学者最初认为的所有视图:来自定义视图的底层 SELECT 数据的预处理副本。因此,DBMS 必须动态维护的是实际数据。SQL Server 上的索引视图是在底层实现和维护的,就好像它们是基表的备用聚集键(从技术上讲,索引视图是一种特定类型的物化视图)。

所以回答原始问题:索引视图的索引实际上确实引用了实际数据,即数据库中某个表中原始数据的副本。

于 2021-11-02T14:52:23.433 回答
0

在 SQL Server 中,索引视图存储视图1的所有数据的副本,非常类似于另一个表。不同之处在于数据的更新方式。

实际上,服务器会在每个基表上生成触发器(但它们不会这样显示)以维护视图的聚集索引中的数据。这就是为什么对索引视图支持的功能有很多限制的原因——它们必须允许自动生成这些“触发器”来维护仅基于伪表inserteddeleted伪表的视图数据。

因此,例如,这就是您不能MAX在索引视图中使用聚合的原因。虽然您可以编写一个有效的insert触发器来处理任何大于 current 的新值MAXupdate或者delete如果当前最大值被更改或删除,触发器可能不得不再次重新扫描整个基表。


1这意味着如果您的查询支持它,或者因为您使用了NOEXPAND提示或者您在企业版上并且优化器喜欢它,那么查询可以只使用视图中的数据而根本不访问基表数据。

于 2021-11-02T14:47:18.903 回答
0

当您索引任何对象时,无论是视图还是表,索引的数据实际上都存储在磁盘上。也就是说,索引始终是物化的,即使源是“虚拟的”。如果索引是针对表的,那么无论何时更改表,都必须更新索引以及由此产生的任何写入操作。

视图也是如此;如果您更改视图中使用的任何源表,则还必须更新索引(更改数据会产生性能成本)。这发生在查询中(在相同的上下文中),对于视图来说它可能很复杂。因此,为了使数据库能够知道何时需要更新这些索引,如果您想拥有一个索引,那么您可以对视图做什么有各种限制。

最后,对于问题中的具体示例,您可以创建Filtered Index,而不是视图加索引。这是直接在表上的索引,但仅适用于满足初始条件的行。

于 2021-11-02T14:49:38.757 回答