我尝试创建索引视图。我终于有了一个(几乎)符合标准的案例。所有内部联接、极少数非确定性函数(已移至外部视图)和自联接仅位于移至外部视图的两个表中。
问题是仅视图就需要 3 秒以上的时间来编译,这对于用例来说太慢了。遵循这样的建议:
索引视图也是提高 INNER JOINS 性能的好方法。当两个或多个表在索引视图中预联接时,查询优化器可以选择检索物化视图数据,而不是执行昂贵的联接操作。
我正在考虑用索引视图解决问题。
然而,一旦创建了这个索引视图(它包含大约 20 个连接),对基础表的每次更新都会变得非常慢。设置统计 IO On 显示它正在重新访问语句上的所有基础表,这些表在重新评估视图时甚至不修改任何数据,例如如下所示的更新:
update a
set y = b.y, z = b.z
from a inner join b on a.x = b.x
where exists (select a.x, a.y, a.z except select b.x, b.y, b.z)
Run Code Online (Sandbox Code Playgroud)
因此,受影响的行数为零,但整个索引视图及其依赖项仍然会执行一系列操作,并且执行时间会显示这一点。
有没有办法让 SQL Server 不使用该视图,除非它确实需要更新记录?也许有我不知道的暗示。
所以我有两个表会造成死锁。应用程序实际上什么都不做,只是在两个不同的事务中更新两个不同的表。这两个表之间存在外键约束(不是级联,只是为了强制完整性),否则就每个事务的发生方式而言,两者之间没有关系。这可能是僵局的全部根源吗?如果是这样,你如何设计外键约束来避免这个问题?
更新:我应该指出(对于那些遇到这个问题的人)根本问题最终与外键约束无关,但是根据这一点,如果另一个外键约束可能导致死锁side 只有主键的聚集索引。
我还了解到死锁 XML 报告没有捕获到那时的整个事务(我错误的假设它确实导致了不正确的问题),这很烦人。
编辑:这两个表是一个名为 KID 的表和一个名为 Image 的表(还有 ZAT_KID 和 ZAT_Image 由触发器填充作为审计跟踪,它们不引用其他任何内容)。Image 的 KIDID 字段是 KIDID 的 KID 主键(聚集索引)的外键。我还应该补充一点,每个堆栈开头的初始选择 1 是数据库池,确保连接在执行其他任何操作之前仍然有效。
这是死锁 XML:
<deadlock-list>
<deadlock victim="processedb6d8">
<process-list>
<process id="processec49b8" taskpriority="0" logused="2672" waitresource="PAGE: 7:1:295182" waittime="2609" ownerId="2771483341" transactionname="implicit_transaction" lasttranstarted="2013-02-05T15:32:48.150" XDES="0x804da410" lockMode="X" schedulerid="2" kpid="10180" status="suspended" spid="93" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2013-02-05T15:32:56.980" lastbatchcompleted="2013-02-05T15:32:56.963" clientapp="Microsoft JDBC Driver for SQL Server" hostname="newappserver" hostpid="0" loginname="DatabaseUser" isolationlevel="read committed (2)" xactid="2771483341" currentdb="7" lockTimeout="4294967295" clientoption1="539099168" clientoption2="128058">
<executionStack>
<frame procname="Database.dbo.T_Audit_KID" line="67" stmtstart="3936" stmtend="5062" sqlhandle="0x030007005776f42cc93b87015aa100000000000000000000">
INSERT INTO …
Run Code Online (Sandbox Code Playgroud)