テーブルから複数の列を選択するクエリのパフォーマンスを改善したいと考えています。列数を制限するとクエリのパフォーマンスに影響があるかどうか疑問に思っていました。
6 に答える
列の数を減らしても、クエリの速度には非常に限定的な影響しかないと思いますが、データの転送速度には大きな影響を与える可能性があります。選択するデータが少ないほど、ネットワーク経由でアプリケーションに転送する必要があるデータも少なくなります。
私は質問を誤解しているかもしれませんが、とにかくここに行きます:
選択する列の絶対数は、大きな違いはありません。ただし、どの列を選択するかは、テーブルのインデックス方法によって大きく異なります。
インデックスでカバーされている列のみを選択している場合、DB エンジンは、テーブル データをフェッチすることなく、クエリにインデックスのみを使用できます。ただし、カバーされていない列を 1 つでも使用すると、行全体を取得する必要があり (キー検索)、パフォーマンスが大幅に低下します。場合によっては、パフォーマンスが大幅に低下し、DB エンジンがインデックスを気にする代わりにフル スキャンを実行することを選択することもあります。選択されている行の数によって異なります。
したがって、列を削除することでこれをカバーするクエリに変えることができれば、はい、パフォーマンスを向上させることができます。そうでなければ、おそらくそうではありません。とにかく目立たない。
SQL Server 2005+ の簡単な例 - これがあなたのテーブルだとしましょう:
ID int NOT NULL IDENTITY PRIMARY KEY CLUSTERED,
Name varchar(50) NOT NULL,
Status tinyint NOT NULL
このインデックスを作成すると:
CREATE INDEX IX_MyTable
ON MyTable (Name)
次に、このクエリは高速になります。
SELECT ID
FROM MyTable
WHERE Name = 'Aaron'
しかし、このクエリは遅くなります(より遅くなります):
SELECT ID, Name, Status
FROM MyTable
WHERE Name = 'Aaron'
インデックスをカバリング インデックスに変更すると、つまり
CREATE INDEX IX_MyTable
ON MyTable (Name)
INCLUDE (Status)
DB エンジンが行を読み取る必要がないため、2 番目のクエリは再び高速になります。
列数を制限しても、クエリに測定可能な影響はありません。ほとんどの場合、行全体がキャッシュにフェッチされます。プロジェクションは、SQL パイプラインの最後に発生します。
処理のプロジェクション部分は、集計の作成を伴う可能性があるため、最後に (たとえば、GROUP BY の後) 発生する必要があります。また、JOIN、WHERE、および ORDER BY 処理には多くの列が必要になる場合があります。最終的に結果セットに返されるよりも多くの列。何らかの方法で I/O を少し節約するために、クエリ プランにプロジェクションを実行するステップを追加する価値はほとんどありません。
クエリ プランのドキュメントを確認してください。クエリ プランに「プロジェクト」ノードはありません。これは、結果セットの定式化の小さな部分です。
「行全体のフェッチ」から逃れるには、列指向 (「反転」) データベースを使用する必要があります。
扱っているサーバー (および MySQL の場合はストレージ エンジン) によって異なります。たとえば、行単位のストレージではなく列単位のストレージを行う MySQL ストレージ エンジンが少なくとも 1 つあります。
他の主な可能性は、テーブルをセグメント化して、一部の列をあるサーバーに格納し、他の列を別のサーバーに格納した場合です (別名、垂直分割)。この場合、より多くの列を取得するには、異なるサーバーからデータを取得する必要がある可能性があり、負荷が不均衡であるため、サーバーによって応答時間が異なる可能性が常にあります。もちろん、通常は負荷を合理的にバランスさせようとするため、これはかなり珍しいことですが、それでも可能です (特に、サーバーの 1 つが他のデータとは独立して使用法が異なる可能性がある他のデータを処理する場合)。
はい、クエリが非クラスター化インデックスでカバーできる場合は、すべてのデータが既にインデックスにあり、ベース テーブル (ヒープがある場合) またはクラスター化インデックスにオプティマイザーが触れる必要がないため、高速になります。
tvanfosson が既に書いていること、つまり「転送」コストがあることを実証するために、クエリ アナライザーから MSSQL 2000 DB で次の 2 つのステートメントを実行しました。
SELECT datalength(テキスト) FROM syscomments
syscomments からテキストを選択
どちらの結果も 947 行を返しましたが、最初の結果は 5 ミリ秒、2 番目の結果は 973 ミリ秒かかりました。
また、フィールドが同じであるため、インデックス作成がここで考慮されるとは思いません。