SQL Server /リンクサーバー/ビューに関連するパフォーマンスの問題があります。私がしたいことを行うための最善の方法は何かを理解していただけると幸いです=)。
いくつかのテストの後、これは状況です:
SELECT * FROM (L1.V1 u L2.V2 u L3.V3) WHERE some filters
を実行すると、パフォーマンスは非常に優れていますSELECT * FROM VK WHERE some filters
を実行すると、ケース1よりもパフォーマンスが低下します。私のソフトウェアでnHbinernateを使用してマップするビューが必要なため、ケース2のパフォーマンスの改善に興味があります...
よろしくお願いします
ジョンアランの投稿後の更新
わかりました、でも結果はありません。私はDBAではありませんが、DB構成に関するスキルは本当に限られています。一歩ずつ進んでもいいですか?
リモートサーバー(called Y
)で、セキュリティ->ログイン->新しいログインによって新しいアカウント(called linkedserver
)を作成しました。ログイン名、SQL認証、パスワードの順に選択します。デフォルトデータベースの場合、master
を選択します。 server roles
タブで、public
を選択します。 User mapping
タブで、リモートクエリに関連するデータベースを選択し、それぞれについてdb_ddladmin
およびpublic
ロールを選択します。次に、リモートクエリに関係するデータベースごとに、リンクサーバーユーザーの有効なアクセス許可を確認しましたが、ALTER
とCREATE
のアクセス許可は多数ありますが、SHOW PLANはありません(その後、これも選択しました)。
Yへのリンクサーバーが存在するデータベースサーバー(called X
)上に、リンクサーバー(called L1
)を作成しました。セキュリティTABで、local user sa
とremote user linkedserver
をパスワードとともに選択しました。
VIEWを使用せずにL1全体でクエリを実行すると、良い結果が得られます。クエリをVIEWの低パフォーマンスに配置しても、何も変更されていません...
何か間違ったことをしたと思いますが、どこかわかりません...
これは、リンクサーバーを使用してビューなしで実行するクエリです。
select * from
(
select * from dolph.agendasdn.dbo.vistaaccettazionegrp
union
select * from dolph.acampanet.dbo.vistaaccettazionegrp
union
select * from municipio.dbnet.dbo.vistaaccettazionegrp
) a
where cognome = 'test' and nome = 'test'
ビューに私はこのコードだけを入れました
select * from dolph.agendasdn.dbo.vistaaccettazionegrp
union
select * from dolph.acampanet.dbo.vistaaccettazionegrp
union
select * from municipio.dbnet.dbo.vistaaccettazionegrp
次にselect * from VIEW where cognome = 'test' and nome = 'test'
に電話しました
そう..
これはばかげていると思います!
実行計画
ビューを使用しない、プレーンクエリの実行プラン:
ビューを使用した実行計画:
あなたの問題は、統計と見積もりで始まり、終わります。サーバーで状況を再現し、興味深いヒントと回避策を見つけました。
まず最初に、実行計画を見てみましょう。
ビューを使用すると、フィルターが適用されたことがわかります後リモートクエリが実行されますが、ビューがないとフィルターはまったく適用されませんでした。真実は、取得する前に、リモートサーバーで、フィルターがinsideRemote Queryに適用されたことです。ネットワーク上のデータ。
まあ、明らかにリモートサーバーでフィルターを適用して、取得するデータを少なくすることは、より良いオプションであり、ビューを使用しない場合にのみ発生することは明らかです。
だから...何がそんなに面白いのですか...?
驚いたことに、フィルターをcognome = 'test'
からcognome = N'test'
(文字列のユニコード表現)に変更すると、ビューは最初のクエリと同じ実行プランを使用しました。
理由は、SQL Serverビューを使用すると、(リモート)クエリから返される行の数が少ないと推定され、ローカルフィルタリングの方が安価であると推定されたためですが、SQL ServerがNVARCHAR
をVARCHAR
に暗黙的に変換するために、統計を使用できなくなり、ローカルでフィルタリングするという決定は行われませんでした。
ローカルで統計を探しましたが、ビューに統計がなかったため、ビューはリモート統計をアドホッククエリが行わない方法で使用しているため、誤った判断を下しています。
OK、それで何が問題を解決しますか?
以前に回避策がある(少なくとも誰かがより良い解決策を見つけるまで)と述べましたが、いいえ、文字列にUnicodeを使用するつもりはありません。
最初に答えを出したかったのですが、それでも理由を見つける必要がありますが、 Inline Function
SQL Serverはクエリ(ビューなし)とまったく同じように動作するので、ビューを関数に置き換えると、単純なクエリで良好なパフォーマンスが得られます(少なくとも私の環境では)。
あなたのための私のコード提案は:
CREATE FUNCTION fn_anagrafiche2()
RETURNS table
AS
RETURN
(
SELECT *
FROM dolph2.agendasdn.dbo.vistaanagraficagrp
UNION
SELECT *
FROM dolph2.acampanet.dbo.vistaanagraficagrp
UNION
SELECT *
FROM municipio2.dbnet.dbo.vistaanagraficagrp
)
GO
クエリは次のようになります。
SELECT *
FROM fn_anagrafiche2()
WHERE cognome = 'prova'
これは私のサーバーで動作しますが、もちろん最初にテストします。
注:SELECT *
を使用することはまったくお勧めしません。将来のエラーが発生しやすいため、単に使用しました。それはあなたの質問にあったので、代わりにこのコメントを追加できるときにそれを変更する必要がなかったからです:)
リンクサーバーと統計に関しては、基本的な制限があります。それらを表示できるのは、リモートの場所に次のいずれかの権限がある場合のみです。
sysadmin
サーバーロールのメンバーdb_owner
またはdb_ddladmin
データベースロールのメンバー通常、あなたは単なるデータリーダーであり、統計情報(ヒストグラムさえも)を見ることができません。その場合、実行計画は影響を受ける傾向があります。
これはSQL Server 2012 SP1で修正されましたが、古いバージョンで実行されているレガシーコードを快適に使用できません。
私がするトリックは次のとおりです:
リモートサーバーでlinked_server
アカウントの権限をdb_ddladmin
として付与します(統計情報を表示できるようにするため)。
Deny実際にdb_ddladmin
が許可するすべてのアカウント:
CREATE TABLE
CREATE VIEW
CREATE PROCEDURE
CREATE FUNCTION
CREATE RULE
等.
セキュリティを損なうことなく魅力のように機能します!