OLTP環境中,使用索引檢視的base資料表最好皆是唯讀。
很久以前我介紹過索引檢視,索引檢視大部分可以帶來極大的效能改善,
BOL建議不要使用異動頻率高資料表來建立索引檢視,
但因為索引檢視提升查詢效能實在讓我難以抵擋誘惑,
所以新系統我抱者試試看心態上線,結果就是花了快3天時間,改寫2百多隻SP、1百多隻function,
最後完完整整刪除索引檢視,才解決blocking query、deadlock、query timeout問題,
拿異動頻率高相關資料表建立索引檢視,結果就是增加blocking並提高deadlock發生機會,
下面我簡單還原我當時系統上線情況
1.更多的blocking
--session 1
begin tran
insert into indexviewtest
select 1,1,1
-- rollback
--session 2
begin tran
insert into indexviewtest
select 2,1,1
rollback
這兩條session在沒有索引檢視下並不會發生blocking。
建立索引檢視
--create indexed view
create view idvtest WITH SCHEMABINDING
as
select c1,
COUNT_BIG(*) AS total
from dbo.indexviewtest
group by c1
create unique clustered index cidx_idvtest
on idvtest(c1)
檢視索引檢視後再次執行上面script後,就可以輕易看到session2被session1 blocking
--create indexed view
create view idvtest WITH SCHEMABINDING
as
select c1,
COUNT_BIG(*) AS total
from dbo.indexviewtest
group by c1
create unique clustered index cidx_idvtest
on idvtest(c1)
2連結資料行資料差異太大,使用索引檢視效能反而更差
BOL提到可以把常用相關資料表連結改寫成索引檢視,但這部分還需考慮資料差異不可過大,
以免查詢效能沒有提升反而變得更差,我簡單測試還原該情況
兩者資料表為1:10001,及一筆父資料有約一萬筆子資料
把這2個資料表連結改用索引檢視
create view Pindexviewtestall WITH SCHEMABINDING
as
select t1.c1, t1.c2, t2.c1 as [cc1], t2.c3
from dbo.Pindexviewtest t1 join dbo.indexviewtest t2 on t1.c1=t2.c2
create unique clustered index cidx_Pindexviewtestall
on Pindexviewtestall(c1,cc1)
執行下面TSQL查詢索引檢視
select c1, c2, cc1, c3
from dbo.Pindexviewtestall
可以看到SQL Server不選用索引檢視,反而採取兩個資料表的full scan,整體執行計畫成本(0.1333)。
相關I/O
使用NOEXPAND 提示強制走索引檢視
select c1, c2, cc1, c3
from dbo.Pindexviewtestall with(NOEXPAND)
整體執行計畫成本變高(1.866)。
I/O一整個暴增。
參考