味方か敵か? SQL Serverを使用して最初の年になっていたとき、SQLServerのビューは白熱した議論の対象でした。遅いので悪いと言われました。しかし、今日はどうですか?
あなたは私が何年も前にいたのと同じ船に乗っていますか?次に、この旅に参加して、SQLビューに関する実際の取引を解明し、SQLビューを可能な限り最速で記述できるようにします。
SQLビューは仮想テーブルです。ビュー内のレコードは、ビュー内のクエリの結果です。ビューで使用されるベーステーブルが更新されるたびに、ビューも更新されます。場合によっては、ビュー内のレコードをテーブルとしてINSERT、UPDATE、およびDELETEすることもできます。自分で試したことはありませんが。
テーブルと同様に、ビューを作成、変更、または削除できます。いくつかの制限付きで、インデックスを作成することもできます。
サンプルコードではSQLServer2019を使用したことに注意してください。
1。 SQLビューの適切な使用法と不適切な使用法を理解する
まず、基本です。
SQLビューとは何ですか?
それは非常に重要です。ドライバーのハンマーとして使用する場合は、SQLビューの高速化を忘れてください。まず、適切な使用法を思い出してみましょう:
- 各ユーザーがデータベースに対して抱く認識に焦点を合わせ、簡素化し、カスタマイズするため。
- セキュリティ上の理由から、ユーザーが表示する必要のある唯一の情報にアクセスできるようにするため。
- 依存アプリを壊さないように、古いテーブルまたは古いスキーマに下位互換性を提供するため。必要な変更がすべて完了するまでは一時的なものです。
- 異なるサーバーからのデータを分割するため。したがって、それらは1つのサーバーまたはインスタンスからの1つのテーブルであるかのように見えます。
SQL Serverビューを使用しない方法は?
- さらに別のビューで再利用される別のビューでビューを再利用します。要するに、深くネストされたビュー。この場合、コードの再利用にはいくつかの欠点があります。
- キーストロークを節約します。これは、指の圧力を減らし、コーディングを加速するように見える最初のものに関連しています。
ビューの不適切な使用は、許可されている場合、ビューを作成する本当の理由をあいまいにします。後でわかるように、実際のメリットは、不適切な使用による認識されたメリットを上回ります。
例
Microsoftの例を見てみましょう。 vEmployee AdventureWorksからの眺め 。コードは次のとおりです:
-- Employee names and basic contact information
CREATE VIEW [HumanResources].[vEmployee]
AS
SELECT
e.[BusinessEntityID]
,p.[Title]
,p.[FirstName]
,p.[MiddleName]
,p.[LastName]
,p.[Suffix]
,e.[JobTitle]
,pp.[PhoneNumber]
,pnt.[Name] AS [PhoneNumberType]
,ea.[EmailAddress]
,p.[EmailPromotion]
,a.[AddressLine1]
,a.[AddressLine2]
,a.[City]
,sp.[Name] AS [StateProvinceName]
,a.[PostalCode]
,cr.[Name] AS [CountryRegionName]
,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
INNER JOIN [Person].[Person] p
ON p.[BusinessEntityID] = e.[BusinessEntityID]
INNER JOIN [Person].[BusinessEntityAddress] bea
ON bea.[BusinessEntityID] = e.[BusinessEntityID]
INNER JOIN [Person].[Address] a
ON a.[AddressID] = bea.[AddressID]
INNER JOIN [Person].[StateProvince] sp
ON sp.[StateProvinceID] = a.[StateProvinceID]
INNER JOIN [Person].[CountryRegion] cr
ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
LEFT OUTER JOIN [Person].[PersonPhone] pp
ON pp.BusinessEntityID = p.[BusinessEntityID]
LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
LEFT OUTER JOIN [Person].[EmailAddress] ea
ON p.[BusinessEntityID] = ea.[BusinessEntityID];
GO
このビューの目的は、従業員の基本情報に焦点を当てています。人材スタッフが必要な場合は、Webページに表示できます。他のビューで再利用されましたか?
これを試してください:
- SQL Server Management Studio 、 AdventureWorksを探します データベース。
- Viewsフォルダーを展開します [HumanResources]。[vEmployee]を探します。
- 右クリックして、依存関係の表示を選択します 。
このビューに依存する別のビューが表示され、それが別のビューに依存する場合、Microsoftは悪い例を示しました。ただし、他のビューの依存関係はありません。
次へ進みましょう。
2。 SQLビューに関する神話を暴く
SQLServerがビューからのSELECTを処理するとき 、WHERE句または外部クエリの結合を処理する前に、ビュー内のコードを評価します。より多くのテーブルが結合されると、ベーステーブルからのSELECTと比較して遅くなります 同じ結果になります。
少なくとも、SQLを使い始めたときに言われたことです。それが神話であるかどうかにかかわらず、それを見つける唯一の方法があります。実際の例を見てみましょう。
SQLビューのしくみ
マイクロソフトは、私たちを暗闇の中に置き去りにして、際限なく議論することはしませんでした。 STATISTICS IO など、クエリがどのように機能するかを確認するためのツールがあります。 および実際の実行計画 。これらをすべての例で使用します。最初のものを用意しましょう。
USE AdventureWorks
GO
SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105
SQL Serverがビューを処理するときに何が起こっているかを確認するために、実際の実行プランを調べてみましょう。 図1で、これを vEmployeeのCREATEVIEWコードと比較します。 前のセクションで。
ご覧のとおり、SQL Serverによって処理される最初のノードは、INNERJOINを使用するノードです。次に、LEFTOUTERJOINの処理に進みます。
WHERE句のFilterノードはどこにも表示されないため、これらのノードの1つに存在する必要があります。すべてのノードのプロパティを調べると、Employeeテーブルで処理されたWHERE句が表示されます。図1のボックスで囲みました。そこにあることを証明するには、そのノードのプロパティについて図2を参照してください。
分析
したがって、 vEmployeeにSELECTステートメントがあります。 WHERE句が適用される前にビューが評価または処理されましたか?実行計画は、そうではなかったことを示しています。そうであった場合は、SELECTノードの最も近くに表示されます。
私が言われたのは神話でした。 SQLビューの適切な使用法を誤解していたため、何か良いことを避けていました。
これで、SQLServerがビューからSELECTを処理する方法がわかりました。 、疑問が残ります:ビューを使用しないよりも遅いですか?
SELECTFROMビューとSELECTFROMベーステーブル–どちらが高速に実行されますか?
まず、 vEmployee内にSELECTステートメントを抽出する必要があります。 ビューを使用したときと同じ結果を表示して生成します。以下のコードは、同じWHERE句を示しています。
USE AdventureWorks
GO
-- SELECT FROM a view
SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105
-- SELECT FROM Base Tables
SELECT
e.[BusinessEntityID]
,p.[Title]
,p.[FirstName]
,p.[MiddleName]
,p.[LastName]
,p.[Suffix]
,e.[JobTitle]
,pp.[PhoneNumber]
,pnt.[Name] AS [PhoneNumberType]
,ea.[EmailAddress]
,p.[EmailPromotion]
,a.[AddressLine1]
,a.[AddressLine2]
,a.[City]
,sp.[Name] AS [StateProvinceName]
,a.[PostalCode]
,cr.[Name] AS [CountryRegionName]
,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
INNER JOIN [Person].[Person] p
ON p.[BusinessEntityID] = e.[BusinessEntityID]
INNER JOIN [Person].[BusinessEntityAddress] bea
ON bea.[BusinessEntityID] = e.[BusinessEntityID]
INNER JOIN [Person].[Address] a
ON a.[AddressID] = bea.[AddressID]
INNER JOIN [Person].[StateProvince] sp
ON sp.[StateProvinceID] = a.[StateProvinceID]
INNER JOIN [Person].[CountryRegion] cr
ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
LEFT OUTER JOIN [Person].[PersonPhone] pp
ON pp.BusinessEntityID = p.[BusinessEntityID]
LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
LEFT OUTER JOIN [Person].[EmailAddress] ea
ON p.[BusinessEntityID] = ea.[BusinessEntityID]
WHERE e.BusinessEntityID = 105
次に、STATISTICS IOを検査し、比較ショープランを実行します 。ベーステーブルからのクエリと比較して、ビューからのクエリにはいくつのリソースが必要ですか?図3を参照してください。
ここで、ビューまたはベーステーブルからのクエリは、同じ論理読み取りを消費します。どちらも19*8KBページを使用しました。これに基づいて、それは誰がより速いかについての結びつきです。つまり、ビューを使用してもパフォーマンスが低下することはありません。 実際の実行計画を比較してみましょう 比較ショープランを使用して両方の :
図の影付きの部分が見えますか? QueryPlanHashはどうですか 両方の?両方のクエリが等しいQueryPlanHash また、同じ操作(ビューテーブルまたはベーステーブルのいずれか)は、SQLServerによって同じように処理されます 。
サンプルの同じ論理読み取りと同じ計画は、両方が同じように実行されることを示しています。したがって、論理読み取りが多いと、ビューを使用するかどうかに関係なく、クエリの実行が遅くなります。この事実を知ることは、問題を修正し、ビューをより速く実行するのに役立ちます。
残念ながら、いくつかの悪いニュースがあります。
SQLビューをテーブルに結合する
前に見たのは、結合のないビューからのSELECTです。ただし、テーブルをビューに結合するとどうなりますか?
別の例を見てみましょう。今回は、 vSalesPersonを使用します AdventureWorksで表示 –連絡先情報と販売割り当てを含む営業担当者リスト。ここでも、ステートメントをベーステーブルのSELECTと比較します。
-- get the total sales orders for each salesperson
-- using the view joined with SalesOrderHeader
SELECT
sp.FirstName
,sp.MiddleName
,sp.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM Sales.vSalesPerson sp
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY sp.LastName, sp.MiddleName, sp.FirstName
-- using base tables
SELECT
p.FirstName
,p.MiddleName
,p.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM sales.SalesPerson sp
INNER JOIN Person.Person p ON sp.BusinessEntityID = P.BusinessEntityID
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY p.LastName, p.MiddleName, p.FirstName
同じだと思われる場合は、STATISTICSIOを確認してください。
驚いた? vSalesPersonに参加する SalesOrderHeaderで表示 テーブルには、ベーステーブル(774 x 8KB)を使用するだけの場合と比較して、膨大なリソース(28,240 x 8KB)が必要です。また、不要なテーブル(赤いボックス内のテーブル)が含まれていることにも注意してください。 SalesOrderHeaderでのより高度な論理読み取りは言うまでもありません ビューを使用する場合。
しかし、それだけではありません。
実際の実行計画はより多くを明らかにします
ベーステーブルへのクエリの実際の実行プランに注意してください:
この図は、かなり正常な実行計画を示しているようです。しかし、ビューのあるものをチェックしてください:
図7の実行プランは、図5のSTATISTICSIOと一致しています。ビューから不要なテーブルを確認できます。 キールックアップもあります 実際の行よりも1,000レコード以上離れている行の推定値を持つノード。最後に、SELECTノードにも警告が表示されます。何でしょうか?
そのExcessiveGrantとは何ですか SELECTノードで警告しますか?
過剰な許可は、許可されたメモリと比較して最大使用メモリが小さすぎる場合に発生します。この場合、1024KBが許可されましたが、使用されたのは16KBのみでした。
Memory Grantは、プランの実行に必要なメモリの推定量(KB単位)です。
キールックアップの見積もりが間違っている可能性があります ノードおよび/またはこれを引き起こした計画に必要のないテーブルを含めること。また、許可されたメモリが多すぎると、ブロッキングが発生する可能性があります。残りの1008KBは、他の操作に役立つ可能性があります。
最終的に、ビューをテーブルに結合すると、問題が発生しました。ベーステーブルからクエリを実行する場合、これらの問題に対処する必要はありません。
要点
長い説明でした。ただし、WHERE句または外部クエリの結合が評価される前に、ビューが評価または処理されないことはわかっています。また、両方が同じように機能することも証明しました。
一方、ビューをテーブルに結合する場合があります。ビューからは必要のないテーブルの結合を使用します。 STATISTICS IOと実際の実行プランを確認しない限り、これらは表示されません。それはすべてパフォーマンスを損なう可能性があり、問題はどこからともなく発生する可能性があります。
したがって:
- ビューを含むクエリが内部からどのように機能するかを知る必要があります。
- STATISTICS IOと実際の実行計画により、クエリとビューがどのように機能するかが明らかになります。
- ビューをテーブルに結合して不注意に再利用することはできません。 STATISTICSIOと実際の実行計画を常に確認してください! ビューを再利用してネストしてコーディングの生産性を「向上」させる代わりに、IntelliSenseとSQLCompleteなどのコード補完ツールを使用します。
そうすれば、正しい結果が得られるがカタツムリのように動作するビューを作成しないようにすることができます。
3。インデックス付きビューをお試しください
インデックス付きビューは、その名前が意味するものです。 SELECTステートメントのパフォーマンスを向上させることができます。ただし、テーブルインデックスと同様に、ベーステーブルが大きく、継続的に更新されると、パフォーマンスに影響を与える可能性があります。
インデックス付きビューがクエリのパフォーマンスをどのように改善できるかを確認するために、 vStateProvinceCountryRegionを調べてみましょう。 AdventureWorksで表示 。ビューはStateProvinceIDでインデックス化されます およびCountryRegionCode 。これは、クラスター化された一意のインデックスです。
インデックスがないビューとインデックスがあるビューのSTATISTICSIOを比較してみましょう。これにより、SQLServerが読み取る8KBページの数を学習します。
この図は、 vStateProvinceCountryRegionにインデックスがあることを示しています。 ビューは論理読み取りを半分に減らします。インデックスがない場合に比べて50%向上しています。
聞いて良かったです。
それでも、不注意にビューにインデックスを追加しないでください。 1つの一意のクラスター化インデックスを持つための厳密なルールの長いリストがあることに加えて、テーブルにインデックスを簡単に追加するのと同じように、パフォーマンスを低下させる可能性があります。また、インデックスを追加した後に論理読み取りが減少した場合は、STATISTICSIOを確認してください。
要点
この例で見たように、インデックス付きビューはSQLビューのパフォーマンスを向上させることができます。
ボーナスのヒント
他のクエリと同様に、SQLビューは次の場合に高速に実行されます。
- 統計が更新されます
- 欠落しているインデックスが追加されます
- インデックスはデフラグされています
- インデックスは適切なFILLFACTORを使用しました
結論
SQLビューは良いですか悪いですか?
SQLビューを正しく記述し、それらがどのように処理されるかを確認すれば、SQLビューは優れています。 STATISTICSIOやActualExecutionPlanなどのツールがあります–それらを使用してください!インデックス付きのビューもパフォーマンスを向上させることができます。
この投稿が好きですか?お気に入りのソーシャルメディアプラットフォームで愛を分かち合ってください。