2009-07-28 8 views
1

これはa previous questionのフォローアップです。'<>'演算子を使用するクエリを最適化できますか?

このクエリを完全なテーブルスキャンを実行しないように最適化するにはどうすればよいですか?

SELECT Employee.name FROM Employee WHERE Employee.id <> 1000; 

explain SELECT Employee.name FROM Employee WHERE Employee.id <> 1000; 
+----+-------------+-------------+------+---------------+------+---------+------+------+-------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+-------------+------+---------------+------+---------+------+------+-------------+ 
| 1 | SIMPLE  | Employee | ALL | PRIMARY  | NULL | NULL | NULL | 5000 | Using where | 
+----+-------------+-------------+------+---------------+------+---------+------+------+-------------+ 

Empoyee.idが明確でない場合には、主キーである。)

+1

Employee.idにインデックスがあることを確認してください。 –

+1

1以外のすべての行が返されていますか?そうであれば、インデックスを使用する理由はほとんどありません。例えば、エンジンがインデックスを使用しないことを決定してもよい。行のnrはかなり低いです。 – nos

答えて

4

は名前とidの被覆率を有し、そしてインデックスを使用してクエリを満たすことができるはずです。テーブルのスキャンがディスクに移動する必要があるのに対し、インデックス全体がすでにメモリに格納されている可能性が高いため、これは高速です。

where句の選択性が低いため、データベースでインデックスを使用するヒントを提供する必要があります。私はSQL Serverのユーザーです。したがって、インデックスをヒントするためにmysqlに必要な構文がわからない場合や、mysqlがこのようにカバリングインデックスを利用できる場合でも、

しかし、私はあなたが多くの改善を得ることはできないと考えています。あなたはそのテーブルをスキャンする必要があるはずです。

+0

+1:ありがとう、これは私が知っていたものですが、接続を確立していない...経験は王様です!さて、私はあなたの編集を見ました:私はそれが少なくとも助けることができる、十分なインテリジェントなDBエンジンを持っていると思う。あなたが得られるのは、 "フルテーブルスキャン"の代わりに "フルインデックススキャン"です。 2列のインデックスは大部分の時間がテーブル全体よりも小さいので、より高速になります(メモリにないときも!)。 – Juergen

+0

災害のようなものを除くすべての行を返すと、テーブルスキャンを実行するか、少なくとも完全なインデックススキャンが実行されます(スキーマとデータによって異なります)。 – MarkR

+0

@マーク:すべてのパノラマ化はなぜですか、彼らはここでフルテーブルスキャンについて?それについて考えてください - 何を返す必要がありますか? 1つを除くすべての従業員名。あなたは少なくともこの情報を読む必要があります。この情報ともう1列(比較のために必要なID)が読み込まれます。私は、リレーショナルモデルでは、より良い解決策は存在しないと言います。もちろん、この特別な問題のために特別なモデルを考えることはできますが、それは正当化されますか? – Juergen

1

従来のデータベースでは、あなたは傾けることができます!

もちろん、指定されたId(キーまたはインデックスがある場合)を持つ従業員をすべて省略することもできますが、通常は足の下にテーブル全体の大半があります。したがって、索引を使用すると事態が複雑になり、通常はftsがより高速なオプションになります。

特殊なデータベースを使用すると、すべての従業員の名前を互いに隣接して格納できます。

編集:私はジョエルのもう一つの答えを見た。実際、あなたの特別インデックスは、今やコンテンツの一部を格納する特別な形式になっているので、これは意味があります。良いデータベースでは、必要な列をカバーするときにインデックスコンテンツを使用できます。もちろん、いわゆる「フルインデックススキャン」(通常はフルテーブルスキャンの方がはるかに速い)でエンディングします。

+0

実際には、テーブルのすべてのレコードをディスクから読み込む必要があるため、インデックスを使用するとパフォーマンスが低下し、増やされないため、これはまったく改善されません。クエリオプティマイザがインデックスを使用するほど愚かであれば(ありがたいことに、これよりスマートです)、完全なテーブルスキャンを実行するために必要なすべてのIO読み取りの上にインデックスページを読み込むために追加のIO操作を追加する必要があります。 –

+0

@Charles:あなたが説明したことは、あまり言葉で言いたくないことです。しかし、Joel氏が話した例外はありますが、少なくともいくつかのデータベースではそうです(誰もがこの最適化を見つけることができないかもしれません)。 – Juergen

1

試してみることがたくさんあります。実際には、データベースエンジンがどのように解析するかによって異なります。いくつかのオプション:

select employee.name from employee where employee.id not in (1000); 

また、より小さい、そしてより大きいを持つユニオンを試すこともできます。

しかし、特定の例では、(実際のケースでは単純すぎるかもしれませんが)テーブルスキャンは必ずしも悪いことではありません。 1つを除いてすべてのレコードを返さなければならない場合、インデックスを使用すると実際には遅くなることがあります。

+0

丁寧であることに加えて、ダウンボートの理由を与えることは、さらなる議論に役立ちます。ただdownvotingはしません。 – Yishai

+0

@Yishai、申し訳ありませんが、あなたは正しいと思います。 データベースは、テーブル内の行を保持するページの20-30%以上を読み取る必要があると判断すると、インデックスをトラバースすることを認識します(索引のレベルごとに1つのI/O操作を必要とする)は、より犠牲になり、とにかくテーブル走査を行います。 –

+0

私は私の最後の段落でそれを言ったと思いました。私の答えの種類は、特定の例ではなく、特定の技術的課題(インデックスフィールドではない)を表すことを意図していると仮定しています。あまりにも多くの時間の質問は、それらを簡単に保つために実際の状況ではありません。 – Yishai

1

パフォーマンスを向上させるものはありません。この場合、データベースはすべてのレコードを保存するように要求するので、完全なテーブルスキャンを実行する必要があります。インデックスのすべてのページを読み込むと、パフォーマンスが低下するだけです。幸いにも、インデックスを追加しても、データベースはそれを無視するほどスマートになります...

EDIT to @Juergens comment。
Juergen、あなたはカバーインデックスについては正しいですが、ここで相反する効果があります。このようなシナリオでインデックスを使用すると、ある意味で悪影響があります...クエリエンジンは、インデックス内の各レベルについて、I/O操作を調べる必要がある各行に対して1つのI/O操作を実行する必要があります。たとえば、索引に5つのレベルがあり、1M行の場合は、完全な表スキャンを実行するには1MのI/Oに比べて5百万回のI/O操作になります。このため、このシナリオでは、ほとんどのクエリオプティマイザが使用可能なインデックスを無視して、テーブルスキャンを実行するのはこのためです。 (ヒントを使用して索引を使用する場合を除きます)唯一の緩和要因は、問合せで必要なすべての属性が索引(索引をカバーする)にあり、ディスク上の1ページあたりの索引行の数がページごとのテーブル行を使用して、クエリによって返された各行のインデックスの各レベルをトラバースしなければならないという悪影響を相殺します。

+0

あなたは正しい方向にあります。しかし、索引が必要なすべての列をカバーしているときに索引からの照会を実行するのに十分なほどスマートなデータベースが存在します。この方法では、特定のデータベース項目のアクセスが節約されます。スマートなデータベースエンジンでは、(id、name)のインデックスを使用してテーブルへのアクセスを回避することができ、フルインデックススキャンのみを実行できます。 – Juergen

+0

IOを必要とする概念は間違っています。レコードごとに個別のIO操作ではありません。 _page_ごとに別々のIO操作です。とにかく1:1になるようにインデックスを設計するので、このインデックスはメモリに保存されるので、ディスクIOはまったくない可能性があります。少なくとも、索引は表よりも小さい可能性があります(彼が私たちに語っていない列がもっと多いと仮定して)読み込む総ページ数はそれほど少なくありません。 –

関連する問題