11

where句がまったくない場合と比較して、値としてLIKEキーワードとワイルドカードを使用すると、クエリのパフォーマンスはどのようになるのでしょうか。

「WHEREALIKE'%'」などのwhere句について考えてみます。これは、列'a'のすべての可能な値と一致します。これは、where句がまったくない場合とどのように比較されますか。

私がこれを尋ねる理由は、ユーザーが検索する値を指定できるいくつかのフィールドがあるアプリケーションがあるからです。場合によっては、ユーザーは考えられるすべての結果を望んでいます。私は現在、次のような単一のクエリを使用しています。

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

'%'および'%'の値は、aおよびまたはbのすべての可能な値に一致するように指定できます。これは、アプリケーションで単一の名前付きクエリを使用できるので便利です。このためのパフォーマンスの考慮事項は何でしょうか。クエリオプティマイザは、LIKE'%'を単純にすべてに一致するように減らしますか?名前付きクエリ(プリペアドステートメント)を使用しているため、回答にも影響する可能性があることに気付きました。答えはおそらくデータベース固有であると思います。つまり、これはOracle、MS SQL Server、およびDerbyでどのように機能するのでしょうか。

これに対する別のアプローチは、ワイルドカードを入力するユーザーに基づいて3つの別々のクエリを使用することです。

Aはワイルドカードクエリです。

SELECT * FROM TableName WHERE b LIKE ?

Bはワイルドカードクエリです。

SELECT * FROM TableName WHERE a LIKE ?

AとBはワイルドカードです。

SELECT * FROM TableName

ワイルドカードなし:

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

明らかに、単一のクエリを持つことは、維持するのが最も簡単で簡単です。それでもパフォーマンスが良好な場合は、1つのクエリのみを使用します。

4

11 に答える 11

13

SQLServerは一般的に

WHERE City LIKE 'A%'

そしてそれを次のように扱います

WHERE City >= 'A' AND City < 'B'

...必要に応じて、インデックスシークを喜んで使用します。私は「一般的に」と言います。これは、特定の場合にこの単純化を実行できないことがわかったためです。

誰かがやろうとしている場合:

WHERE City LIKE '%ville'

...その場合、インデックスシークは本質的に不可能になります。

しかし、次のような単純なものです。

WHERE City LIKE '%'

以下と同等と見なされます:

WHERE City IS NOT NULL
于 2009-10-22T02:35:37.570 に答える
4

これに対する教科書の答えがあることを望んでいましたが、データベースの種類によって大きく異なるようです。ほとんどの回答は、私が行ったこととまったく同じようにテストを実行する必要があることを示していました。

私のアプリケーションは、主にDerby、MS SQL、およびOracleデータベースを対象としています。ダービーは組み込みで実行でき、セットアップも簡単なので、最初にそのパフォーマンスをテストしました。結果は驚くべきものでした。かなり大きなテーブルに対して最悪のシナリオをテストしました。テストを1000回実行し、結果を平均しました。

クエリ1:

SELECT * FROM TableName

クエリ2(a = "%"およびb = "%"の値を使用):

SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?

クエリ1の平均時間:178ミリ秒

クエリ2の平均時間:181ミリ秒

したがって、ダービーのパフォーマンスは2つのクエリ間でほぼ同じです。

于 2009-10-26T16:35:51.527 に答える
4

DBMSが提供するクエリ分析(EXPLAINMySQLの場合SET SHOWPLAN_ALL ON、MS SQLの場合(または他の方法のいずれかを使用する場合、EXPLAIN PLAN FOROracleの場合))を使用して、クエリがどのように実行されるかを確認できます。

于 2009-10-22T02:42:14.863 に答える
2

Oracle 10gR2は、この状況に対して特別な最適化を実行しているようには見えませんが、LIKE'%'がnullを除外していることを認識しています。

create table like_test (col1)
as select cast(dbms_random.string('U',10) as varchar2(10))
from dual
connect by level <= 1000
/
insert into like_test values (null)
/
commit
/

exec dbms_stats.gather_table_stats(user,'like_test')

explain plan for
select count(*)
from   like_test
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from   like_test
where  col1 like '%'
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from   like_test
where  col1 is not null
/
select plan_table_output from table(dbms_xplan.display)
/

...与える..。

Plan hash value: 3733279756

------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Cost (%CPU)| Time     |
------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |            |          |
|   2 |   TABLE ACCESS FULL| LIKE_TEST |  1001 |     3   (0)| 00:00:01 |
------------------------------------------------------------------------

... と ...

Plan hash value: 3733279756

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    10 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| LIKE_TEST |  1000 | 10000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("COL1" LIKE '%')

... と ...

Plan hash value: 3733279756

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     1 |    10 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |           |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| LIKE_TEST |  1000 | 10000 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("COL1" IS NOT NULL)

TABLE ACCESS FULL行のカーディナリティ(行)に注意してください

于 2009-10-22T06:47:33.900 に答える
2

その塩に値するDBMSはLIKE '%'、クエリを実行しようとする前に句を削除します。DB2/zが実行プランでこれを実行するのを見たことがあると確信しています。

プリペアドステートメントは、実行エンジンに到達する前に実際のSQLに変換する必要があるため、違いはありません。

しかし、すべての最適化の質問と同様に、測定して、推測しないでください!DBAが存在するのは、実際のデータ(時間の経過とともに変化する)に基づいてDBMSを常に調整しているためです。最低限、適切な静的データを使用してすべてのバリエーションの時間を計り(そして実行プランを取得して)、違いがあるかどうかを確認する必要があります。

私は次のようなクエリを知っています:

select c from t where ((1 = 1) or (c = ?))

実行前にwhere句全体を削除するように最適化されています(とにかくDB2で、質問する前に、where句の効果を削除する必要があるが、パラメータプレースホルダーを維持する必要がある場合にコンストラクトが役立ちます(JavaScriptでBIRTを使用してクエリを変更します)ワイルドカードの場合))。

于 2009-10-22T02:24:59.073 に答える
2

Derbyは、使用された実際のクエリプランを調べるためのツールも提供しているため、Derbyを使用して実験を実行し、Derbyが選択したクエリプランを確認できます。-Dderby.language.logQueryPlan = trueを指定してDerbyを実行すると、Derbyはクエリプランをderby.logに書き込むか、ここで説明するようにRUNTIMESTATISTICS機能を使用できます:http://db.apache.org/derby/ docs / 10.5 / Tuning / ctundepth853133.html

DerbyがALIKE'%'を事前に削除するかどうかはわかりませんが、その句が存在すると、実行速度が大幅に低下するとは思いません。

A LIKE'%'句が設定されている場合と設定されていない場合で、環境で取得される実際のクエリプランの出力を確認することに非常に興味があります。

于 2009-10-22T04:34:48.677 に答える
1

LIKE述部がどのように構成されているか、およびテストしているフィールドによっては、全表スキャンが必要になる場合があります。意味的には、「%」は全表スキャンを意味する場合がありますが、SQLServerはクエリに対して内部的にあらゆる種類の最適化を実行します。したがって、質問は次のようになります。SQLServerは、「%」で形成されたLIKE述語を最適化し、WHERE句からスローしますか?

于 2009-10-22T02:28:11.127 に答える
1

議論に欠けていると思う1つの側面は、OPが準備されたステートメントを使用したいという事実です。ステートメントが準備されるとき、データベース/オプティマイザーは他の人が言及した単純化を実行することができずa like '%'、実際の値が準備時にわからないため、最適化することはできません。

したがって:

  • プリペアドステートメントを使用する場合は、4つの異なるステートメント(0、aのみ、bのみ、両方)を用意し、必要に応じて適切なステートメントを使用します。
  • 1つのステートメントだけに固執するときにプリペアドステートメントを使用しない場合にパフォーマンスが向上するかどうかを確認します(ただし、「空の」条件を含めないのは非常に簡単です)
于 2009-10-22T10:13:18.587 に答える
0

列にnull以外の空白値がある場合はどうなりますか?あなたのクエリはおそらくそれに一致します。

これが実際のアプリケーションのクエリである場合は、最新のSQLデータベースのフリーテキストインデックス機能を使用してみてください。パフォーマンスの問題は重要ではなくなります。

if(AB)search ab else(A)search a else B searchbelseの単純なifステートメントはユーザーに何も指定しなかったことを通知します

LIKE演算子について仮定する代わりに、保守が簡単で、理解しやすくなります。「Aが見つかりましたxを検索しました」または「ABを検索しました...」という結果を表示するときに、UIでこれを行う可能性があります。

于 2009-10-22T02:46:00.500 に答える
0

あなたが説明している種類のパラメータでプリペアドステートメントを使用することの価値がわかりません。その理由は、クエリオプティマイザをだまして、どのパラメータが'%'であるかによっては完全に間違った実行プランを準備する可能性があるためです。

たとえば、ステートメントが列Aのインデックスを使用して実行プランで作成されたが、列Aのパラメーターが'%'であることが判明した場合、パフォーマンスが低下する可能性があります。

于 2009-10-22T02:49:55.220 に答える
-2

唯一の述語として「like'%'」を含むwhere句は、nowhere句とまったく同じように動作します。

于 2009-10-22T03:14:14.767 に答える