我有两个表,每个表大约有 500k 行(并且还在增长)。这些不断发生插入/更新,有时每分钟 100 次。系统在基本插入这些表时存在性能问题,即超时。我们已经调整了索引,并进行了通常的优化。但我想知道这两个表在 5 个视图中被大量连接引用的事实是否可能是有害的。我一直认为,也许是错误的,随着基础表的变化,引用它们的视图也会发生变化。因此,如果表格变化如此之大,那么我们的系统可能会因为不得不不断地追赶更新视图而不堪重负。
4 回答
除非它们是索引视图(您在问题中没有提到这一点),否则它们根本不会“更新”。
普通视图类似于 C 中的宏——它们只是隐藏较大表达式的一部分的便捷简写。它们被扩展为引用它们的任何语句的解析树,然后在使用点编译和优化整个树。
对于索引视图,您在很大程度上是正确的 - 视图作为在基表中执行更改的同一事务的一部分进行维护。但是,索引视图的规则已经过设计,因此此更新活动不应招致太大的损失(无需重新查询整个基表即可维护它们)。
这取决于:
1) 如果视图没有被索引,则视图被展开
-- View definition
CREATE VIEW Sales.v_SalesOrderDetail
AS
SELECT h.SalesOrderID, h.SalesOrderNumber, h.OrderDate,
d.SalesOrderDetailID, d.OrderQty, d.UnitPrice, d.LineTotal,
p.ProductID, p.Name AS ProductName, p.Color AS ProductColor
FROM Sales.SalesOrderHeader h
INNER JOIN Sales.SalesOrderDetail d ON h.SalesOrderID = d.SalesOrderID
INNER JOIN Production.Product p ON d.ProductID = p.ProductID
GO
-- View usage
SELECT v.SalesOrderDetailID, v.OrderQty, v.UnitPrice, v.ProductName
FROM Sales.v_SalesOrderDetail v
WHERE v.ProductColor='Red';
GO
如果我们查看执行计划(SSMS:Ctrl + M),
我们会看到视图(FROM Sales.v_SalesOrderDetail v
)被展开,服务器只查询两个表:Sales.SalesOrderDetail d
和Production.Product p
。此外,我们可以看到和之间的连接是如何Sales.SalesOrderHeader h
被Sales.SalesOrderDetail d
删除的,因为:
SELECT
子句 (SELECT v.SalesOrderDetailID, v.OrderQty, v.UnitPrice, v.ProductName
) 不包括表中的列Sales.SalesOrderHeader
,在这两个表之间有一个外键约束和
这个 FK 约束是可信的。
2)如果视图被索引(意味着视图上有UNIQUE CLUSTERED INDEX
定义)并且SQL Server版本是企业版,那么视图可以扩展或不扩展。如果 edition <> enterprise 则展开索引视图。我们可以通过使用提示强制服务器不展开[indexed] 视图:NOEXPAND
-- View definition
CREATE VIEW Sales.v_SalesOrderDetail2
WITH SCHEMABINDING
AS
SELECT h.SalesOrderID, h.SalesOrderNumber, h.OrderDate,
d.SalesOrderDetailID, d.OrderQty, d.UnitPrice, d.LineTotal,
p.ProductID, p.Name AS ProductName, p.Color AS ProductColor
FROM Sales.SalesOrderHeader h
INNER JOIN Sales.SalesOrderDetail d ON h.SalesOrderID = d.SalesOrderID
INNER JOIN Production.Product p ON d.ProductID = p.ProductID
GO
-- Defining the UNIQUE CLUSTERED INDEX
CREATE UNIQUE CLUSTERED INDEX PK_v_SalesOrderDetail2
ON Sales.v_SalesOrderDetail2 (SalesOrderDetailID);
GO
-- View usage
SELECT v.SalesOrderDetailID, v.OrderQty, v.UnitPrice, v.ProductName
FROM Sales.v_SalesOrderDetail2 v WITH (NOEXPAND)
WHERE v.ProductColor='Red';
GO
在这种情况下,我们可以看到执行计划中
包含了Clustered Index Scan PK_v_SalesOrderDetail2
操作符。因此,它使用在第二个视图上定义的索引。
SQLServer 视图没有缓存,因此每次请求视图时都会执行查询
调整索引很好,但可能值得考虑更新这些索引的统计信息的频率和时间。此外,使用缓冲表来保存插入,然后可以每隔 5 或 10 分钟或任何适合您的系统的批量操作插入这些插入可能会有所帮助(将其放在单独的物理磁盘上是个好主意。)这样做会使在 90% 的时间里选择快得多,在其他 10% 的时间里不会比当前差多少。