web-dev-qa-db-ja.com

SELECT *がすべての列を(別の列の順序で)名前で選択するよりもはるかに速いのはなぜですか?

列a、b、c、d、e、f、g、h、i、j、kを含むテーブルでは、次のようになります。

select * from misty order by a limit 25;
Time: 302.068 ms

そして:

select c,b,j,k,a,d,i,g,f,e,h from misty order by a limit 25;
Time: 1258.451 ms

列による選択を速くする方法はありますか?

更新:

テーブルにインデックスがなく、新しく作成されたインデックス

以下はEXPLAIN ANALYZEですが、あまり役に立ちません。

explain analyze select * from misty order by a limit 25;

Limit  (cost=43994.40..43994.46 rows=25 width=190) (actual time=404.958..404.971 rows=25 loops=1)
->  Sort  (cost=43994.40..45731.11 rows=694686 width=190) (actual time=404.957..404.963 rows=25 loops=1)
     Sort Key: a
     Sort Method: top-N heapsort  Memory: 28kB
     ->  Seq Scan on misty  (cost=0.00..24390.86 rows=694686 width=190) (actual time=0.013..170.945 rows=694686 loops=1)
Total runtime: 405.019 ms
(6 rows)

そして:

explain analyze select c,b,j,k,a,d,i,g,f,e,h from misty order by a limit 25;

Limit  (cost=43994.40..43994.46 rows=25 width=190) (actual time=1371.735..1371.745 rows=25 loops=1)
->  Sort  (cost=43994.40..45731.11 rows=694686 width=190) (actual time=1371.733..1371.736 rows=25 loops=1)
     Sort Key: a
     Sort Method: top-N heapsort  Memory: 28kB
     ->  Seq Scan on misty  (cost=0.00..24390.86 rows=694686 width=190) (actual time=0.015..516.355 rows=694686 loops=1)
Total runtime: 1371.797 ms
(6 rows)
12
Evgeny

これはpgsql-hackersメーリングリストに投稿され、私は tried に簡単に回答します。ターゲットリスト(指定された列)がリレーションのタプル記述子と正確に一致する場合、つまり、列の数と順序の両方が一致する場合、基になるスキャンは、囲まれたSortノードによって直接消費可能なタプルを返すことができます。一方、ターゲットリストが一致しない場合(順序または指定された列の数のいずれか)、スキャンは、追加の作業を実行するためにソートのデータ準備手順を必要とするタプルの形式を返します(内部タプル形式から並べ替えコードで直接使用できる形式)。

ちなみに、「*」は内部的に関係のタプル記述子と(直感的に)一致するリストに変換されます。

編集:後者のEXPLAIN ANALYZEのSeq Scanの実際の時間を見ると、それが前のものより多いことがわかります。これは、スキャンが追加の投影ステップを実行した(つまり、ヒープタプルを内部値[]、nulls []形式に変換する)ために発生しました。そして、それが発生したため、上部のSortノードは、データの初期化で追加の作業を行う必要がありました。それは、実際のソート手順が理解できるタプル形式に変換し直すことです。これは、Sortの初期コストから明らかです。それは前者の場合には起こりません。つまり、スキャンはタプルをそのまま返し、ソートの初期化ステップはそれを単にコピーします。

12
amitlan