レコードセットでの結合の効果
ODBCトレースシリーズの6番目で最後の記事では、AccessがAccessクエリの結合をどのように処理するかを見ていきます。前回の記事では、Accessによってフィルターがどのように処理されるかを見ました。式に応じて、Accessはそれをパラメーター化することを選択するか、すべての入力データをダウンロードしてローカルで評価を実行することにより、それ自体を評価するように強制される場合があります。この記事では、結合に焦点を当てます。あなたがそれについて考えるとき、結合は実際には特別な種類のフィルターです。したがって、理論的には、Accessは結合があっても可能な限りリモートにする必要があります。通常、次の疑似SQLで記述された結合が表示される場合があります。
FROM a INNER JOIN b ON a.ID = b.IDただし、次の構文と同等と見なすことができます。
FROM a, b WHERE a.ID = b.IDこれは、より読みやすく親しみやすい
JOIN..ON
を使用してもよいことを示しています。 、AccessはそれをWHERE
として自由に扱うことができます これは、Accessがクエリを完全にリモート化できない状況で役立ちます。しかし、ここに問題があります…Accessはいつ参加をリモート化することを決定しますか?簡単な結合クエリを試してみましょう: SELECT c.CityID ,c.StateProvinceID ,c.CityName ,s.StateProvinceName FROM Cities AS c INNER JOIN StateProvinces AS s ON c.StateProvinceID = s.StateProvinceID;そのクエリをトレースすると、次の出力が表示されます。
SQLExecDirect: SELECT "c"."CityID" ,"s"."StateProvinceID" FROM "Application"."Cities" "c", "Application"."StateProvinces" "s" WHERE ("c"."StateProvinceID" = "s"."StateProvinceID" ) SQLPrepare: SELECT "CityID" ,"CityName" ,"StateProvinceID" FROM "Application"."Cities" WHERE "CityID" = ? SQLExecute: (GOTO BOOKMARK) SQLPrepare: SELECT "StateProvinceID" ,"StateProvinceName" FROM "Application"."StateProvinces" WHERE "StateProvinceID" = ? SQLExecute: (GOTO BOOKMARK) SQLPrepare: SELECT "StateProvinceID" ,"StateProvinceName" FROM "Application"."StateProvinces" WHERE "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? OR "StateProvinceID" = ? SQLExecute: (MULTI-ROW FETCH) SQLPrepare: SELECT "CityID" ,"CityName" ,"StateProvinceID" FROM "Application"."Cities" WHERE "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH)元のAccessクエリはSQLServerで完全に実行できますが、Accessは結合をリモート化しないことを決定しました。代わりに、シータ結合の各テーブルからIDを取得し、2つのダイナセットタイプのレコードセットを開いたかのように、2つの個別のクエリチェーンを設定します。次に、準備された2つの異なるクエリに、最初のクエリからそれぞれのテーブルのキーが供給されます。予想通り、それはネットワークを介して多くのおしゃべりになる可能性があります。
同じAccessクエリをデフォルトのdynaset-typeではなくsnapshot-typeに変更すると、次のようになります。
SQLExecDirect: SELECT "c"."CityID" ,"c"."CityName" ,"c"."StateProvinceID" ,"s"."StateProvinceName" FROM "Application"."Cities" "c", "Application"."StateProvinces" "s" WHERE ("c"."StateProvinceID" = "s"."StateProvinceID" )したがって、スナップショットタイプのクエリの場合、Accessは結合をリモートで実行します。 Accessが元のdynasetタイプのクエリでそれを行わなかったのはなぜですか?手がかりは、次のスクリーンショットにあり、両方を編集しようとしています。 次のスクリーンショットのテーブルの列:
このようなクエリにより、両方の列を更新できます。これはSQLでは実際には表現できませんが、そのようなアクションはユーザーが実行するのに合法です。したがって、その更新を実行するために、Accessは次のODBCSQLを送信します。
SQLExecDirect: UPDATE "Application"."StateProvinces" SET "StateProvinceName"=? WHERE "StateProvinceID" = ? AND "StateProvinceName" = ? SQLExecDirect: UPDATE "Application"."Cities" SET "CityName"=? WHERE "CityID" = ? AND "CityName" = ? AND "StateProvinceID" = ?Accessが各テーブルを更新するために必要な情報を持っていなかった場合、それは不可能でした。これは、Accessが元のdynasetタイプのクエリを解決するときに結合をリモート化しないことを選択した理由を説明しています。ここでの教訓は、クエリを更新可能にする必要がなく、結果のデータが十分に小さい場合は、クエリをスナップショットタイプに変換する方がよい場合があるということです。複雑なレコードソースを作成する必要がある場合は、通常、アクセス側で結合を行うよりも、SQLビューをベースとして使用するとはるかに優れたパフォーマンスが得られます。
これを証明するために、SQLビューを作成し、Accessにリンクします:
CREATE VIEW dbo.vwCitiesAndStates AS SELECT c.CityID ,c.StateProvinceID ,c.CityName ,s.StateProvinceName FROM Application.Cities AS c INNER JOIN Application.StateProvinces AS s ON c.StateProvinceID = s.StateProvinceID;次に、Accessクエリを次のように調整します。
SELECT c.CityID ,c.StateProvinceID ,c.CityName ,c.StateProvinceName FROM vwCitiesAndStates AS c;その後、最初に試した更新を繰り返すと、次のトレースされたODBCSQLが表示されます。
SQLExecDirect: SELECT "c"."CityID" FROM "dbo"."vwCitiesAndStates" "c" SQLPrepare: SELECT "CityID" ,"StateProvinceID" ,"CityName" ,"StateProvinceName" FROM "dbo"."vwCitiesAndStates" WHERE "CityID" = ? SQLExecute: (GOTO BOOKMARK) SQLPrepare: SELECT "CityID" ,"StateProvinceID" ,"CityName" ,"StateProvinceName" FROM "dbo"."vwCitiesAndStates" WHERE "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? OR "CityID" = ? SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (MULTI-ROW FETCH) SQLExecute: (GOTO BOOKMARK) SQLExecDirect: UPDATE "dbo"."vwCitiesAndStates" SET "CityName"=?, "StateProvinceName"=? WHERE "CityID" = ? AND "StateProvinceID" = ? AND "CityName" = ? AND "StateProvinceName" = ?これは、SQLビューを使用して結合を「リモート」すると、Accessは2つのテーブルではなく、単一のソースでのみ機能し、ビューの更新をSQLServerに完全にリモート化することを示しています。副作用の1つは、この更新が次のエラーメッセージで失敗することです。
UPDATE
を実行していたので、これは驚くべきことではありません。 元の例では、Accessは実際には2つを密かに発行していました。 別のUPDATE
個々のテーブルのステートメント。うまくいけば、特に更新可能である必要がある場合に、Accessクエリ/レコードソース/行ソースで結合を行わないようにする必要があるというケースを作るのに役立ちます。そうでない場合は、可能な場合はスナップショットを使用してください。
異種結合に関する簡単なメモ
2つの異なるODBCデータソースからの2つのリンクされたテーブル間の結合についてコメントする必要があります。各データソースは相互に認識していないと想定されるため、Accessは結合をローカルで処理する必要があるため、このような結合は「異種」です。ダイナセットタイプまたはスナップショットタイプのレコードセットを指定するかどうかに関係なく、Accessは各データソースからキーのフルセットをフェッチし、各データソースに個別のパラメーター化されたクエリを送信して結合を解決する必要があります。更新が許可されている場合、Accessは別のUPDATE
を作成します 更新が必要な各データソースにクエリを実行します。また、2つの異なるデータベースからの2つのリンクされたテーブル間の結合は、Accessによって異種と見なされることに注意することも重要です。これは、2つのデータベースが同じサーバー上にあり、データベース間クエリを実行しても問題がない場合でも当てはまります。このシナリオでは、SQLビューは、この記事ですでに見たものと同様に、Accessからクロスデータベース結合を非表示にすることで、追加のチャタリングを削減するのに役立ちます。
外部結合構文の違い
外部結合がAccessクエリの更新可能性に影響を与えない限り、Accessは内部結合バージョンの処理と同様に処理します。左結合であったのと同じクエリを変更すると、トレースされたODBCSQLは次のようにキーポピュレーションクエリを出力します。
SQLExecDirect: SELECT "c"."CityID" ,"s"."StateProvinceID" FROM {oj "Application"."Cities" "c" LEFT OUTER JOIN "Application"."StateProvinces" "s" ON ("c"."StateProvinceID" = "s"."StateProvinceID" ) }構文は、他のSQLダイアレクトで期待されるものとはかなり異なります。これは、ODBC SQL文法では、外部結合を
{oj ...}
でラップする必要があるためです。 表現。その構文の詳細については、ドキュメントを参照してください。私たちの目的では、{oj
を無視することができます そして最後の}
ノイズとして。 結論
結合は一種のフィルターであるかのように扱われ、Accessは許可されている場所で結合をリモート化しようとします。細心の注意を払うべき1つの特定の領域は、デフォルトでdynasetタイプのレコードセットを使用し、Accessはレコードセット内の列の変更を許可するかどうかについての仮定を行わず、それを可能にするために邪魔にならないという事実です。標準SQLでは実際には簡単に表現できない2つのテーブルに更新します。結果として、Accessは、パフォーマンスに悪影響を与える可能性のある結合を含むクエリの更新可能性をサポートするために、さらに多くの作業を行います。
Accessクエリで表現された結合の代わりにSQLビューを使用することで、ペナルティを回避できます。トレードオフは、SQLビューの更新可能性ルールに従うことです。 2つのテーブルを同時に更新することは許可されていない可能性があります。通常、適切に設計されたアクセスフォームは、更新する単一のテーブルのみを表すため、これはそれほど制限ではなく、従うべき適切な規律です。
これで、現在のシリーズが完成しました。しかし、シリーズがうまくいけば火花を散らすという学習は行われるべきではありません。このシリーズがお役に立てば幸いです。また、ODBCデータソースを使用するAccessアプリケーションのパフォーマンスの問題を分析して対処するためのツールを使用して得た新しい洞察についてお聞きすることを楽しみにしています。コメントを残したり、詳細をリクエストしたりして、一緒に読んでくれてありがとう!
Microsoft Accessに関連するものについてさらにサポートが必要な場合は、773-809-5456の専門家に電話するか、[email protected]に電子メールを送信してください。