48

私たちの製品には汎用検索エンジンがあり、検索パフォーマンスを最適化しようとしています。クエリで使用されるテーブルの多くは、NULL 値を許可します。最適化のために null 値を許可しないようにテーブルを再設計する必要がありますか?

当社の製品は と の両方Oracleで動作しMS SQL Serverます。

4

8 に答える 8

14

Quassnoiの受け入れられた回答に対するDavid Aldridgeのコメントに特別な注意を引くための追加の回答。

ステートメント:

このクエリ:

SELECT * FROM テーブルの WHERE 列が NULL です

常にフル テーブル スキャンを使用します

真実ではない。リテラル値を持つインデックスを使用した反例を次に示します。

SQL> create table mytable (mycolumn)
  2  as
  3   select nullif(level,10000)
  4     from dual
  5  connect by level <= 10000
  6  /

Table created.

SQL> create index i1 on mytable(mycolumn,1)
  2  /

Index created.

SQL> exec dbms_stats.gather_table_stats(user,'mytable',cascade=>true)

PL/SQL procedure successfully completed.

SQL> set serveroutput off
SQL> select /*+ gather_plan_statistics */ *
  2    from mytable
  3   where mycolumn is null
  4  /

  MYCOLUMN
----------


1 row selected.

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'))
  2  /

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------
SQL_ID  daxdqjwaww1gr, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ *   from mytable  where mycolumn
is null

Plan hash value: 1816312439

-----------------------------------------------------------------------------------
| Id  | Operation        | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |      1 |        |      1 |00:00:00.01 |       2 |
|*  1 |  INDEX RANGE SCAN| I1   |      1 |      1 |      1 |00:00:00.01 |       2 |
-----------------------------------------------------------------------------------

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

   1 - access("MYCOLUMN" IS NULL)


19 rows selected.

ご覧のとおり、インデックスが使用されています。

よろしく、ロブ。

于 2009-06-20T09:07:38.510 に答える
7

私はテストが必要だと言いますが、他の人の経験を知ることは素晴らしいことです. ms sql サーバーでの私の経験では、null は大きなパフォーマンスの問題 (違い) を引き起こす可能性があり、実際に発生します。非常に単純なテストで、テーブル create ステートメントの関連フィールドに null が設定されていない場合は 45 秒でクエリが返され、設定されていない場合は 25 分以上かかりました (待機をあきらめて、推定クエリ プラン)。

テスト データは 100 万行 x 20 列で、i5-3320 通常の HD および 8GB RAM (2GB を使用する SQL Server) / Windows 8.1 上の SQL Server 2012 Enterprise Edition で 62 個のランダムな小文字のアルファベットから構成されます。テストを現実的な「より悪い」ケースにするために、ランダムなデータ/不規則なデータを使用することが重要です。どちらの場合も、テーブルが再作成され、ランダム データが再ロードされました。これには、適切な量の空き領域が既にあるデータベース ファイルで約 30 秒かかりました。

select count(field0) from myTable where field0 
                     not in (select field1 from myTable) 1000000

CREATE TABLE [dbo].[myTable]([Field0] [nvarchar](64) , ...

 vs

CREATE TABLE [dbo].[myTable]([Field0] [nvarchar](64) not null,

パフォーマンス上の理由から、どちらにもテーブル オプション data_compression = page set があり、それ以外はすべてデフォルトに設定されていました。索引なし。

alter table myTable rebuild partition = all with (data_compression = page);

null を持たないことは、私が特に使用していないインメモリ最適化テーブルの要件ですが、SQL Server は明らかに最速の処理を行います。この特定のケースでは、データに null を持たず、テーブル作成。

このテーブルに対する同じ形式の後続のクエリはすべて 2 秒で返されるため、標準のデフォルト統計と、(1.3GB) テーブルがメモリに収まる可能性があると想定します。すなわち

select count(field19) from myTable where field19 
                       not in (select field18 from myTable) 1000000

null を持たず、null のケースを処理する必要がないということは別として、クエリはより単純になり、短くなり、エラーが発生しにくくなり、通常は非常に高速になります。可能な限り、明示的に必要であり、ソリューションから合理的に解決できない場合を除いて、少なくとも ms sql サーバーでは一般に null を回避することをお勧めします。

新しいテーブルから始めて、これを最大 10m 行 / 13GB の同じクエリにサイズ変更するには 12 分かかります。これは、ハードウェアと使用中のインデックスがないことを考えると非常に立派です。情報クエリは完全に IO バウンドで、IO は 20MB/s から 60MB/s の間でホバリングしていました。同じクエリの繰り返しには 9 分かかりました。

于 2014-10-19T00:47:00.837 に答える
3

パフォーマンスに影響するという理由で Null を使用するかどうかの問題は、データベース設計のバランスを取る作業の 1 つです。ビジネス ニーズとパフォーマンスのバランスを取る必要があります。

必要に応じてヌルを使用する必要があります。たとえば、テーブルに開始日と終了日があるとします。レコードが作成された時点では、終了日がわからないことがよくあります。したがって、パフォーマンスに影響するかどうかに関係なく、データを挿入する必要がないため、null を許可する必要があります。ヌル。これにより、パフォーマンスが向上し、コーディングが少し簡単になり、データの整合性が確実に維持されます。

null を許可しないように変更したい既存のデータがある場合は、その変更の影響を考慮する必要があります。まず、現在 null になっているレコードにどのような値を入力する必要があるか知っていますか? 第二に、またはを使用しているコードがたくさんありますisnullか?coalesceどちらを更新する必要がありますか (これらはパフォーマンスを低下させるため、チェックする必要がなくなった場合はコードを変更する必要があります)。デフォルト値が必要ですか? あなたは本当に1つを割り当てることができますか?そうでない場合、フィールドを null にすることができないと見なされていない場合、挿入または更新コードの一部が壊れます。null を取り除けるように、不適切な情報を入力することがあります。そのため、価格フィールドには 10 進数の値や「不明」などを含める必要があるため、適切に 10 進数のデータ型にすることはできず、計算を行うためにあらゆる種類の長さに移動する必要があります。これにより、作成された null と同じかそれ以上のパフォーマンスの問題が発生することがよくあります。さらに、すべてのコードを確認する必要があり、null であるフィールドまたは null でないフィールドへの参照を使用した場所はどこでも、

私はクライアント データから多くのデータ インポートを行っていますが、null を許可する必要があるフィールドが許可されていないファイルを取得するたびに、システムにインポートする前にクリーンアップする必要があるガベージ データを取得します。メールもその一つです。多くの場合、データはこの値を知らずに入力されます。これは通常、何らかのタイプの文字列データであるため、ユーザーはここに何でも入力できます。メールをインポートして、「わからない」ことを見つけます。実際に「わからない」にメールを送ろうとするのは大変です。システムが有効な電子メール アドレスを要求し、@ 記号の存在などをチェックする場合、「I@dont.know」というメッセージが返されます。このようなガベージ データは、データのユーザーにとってどのように役立ちますか?

null に関するパフォーマンスの問題の一部は、sargable でないクエリを記述した結果です。場合によっては、必要な null を削除するのではなく、where 句を再配置するだけでパフォーマンスが向上することがあります。

于 2009-06-19T17:15:55.853 に答える
0

私の経験では、NULLは有効な値であり、通常は「わからない」という意味です。わからない場合は、列のデフォルト値を作成したり、NOTNULL制約を適用しようとしたりすることは実際には無意味です。NULLはたまたま特定のケースです。

NULLの本当の課題は、検索が少し複雑になることです。たとえば、WHERE column_name IN(NULL、'value1'、'value2')とは言えません。

個人的には、列がたくさんある場合、または特定の列にNULLがたくさん含まれている場合は、データモデルを再検討することをお勧めします。たぶん、それらのnull列を子テーブルに入れることができますか?例:名前、自宅の電話番号、携帯電話、faxno、勤務先番号、緊急番号などの電話番号が記載されたテーブル。これらのうち1つまたは2つだけを入力すると、正規化する方が適切です。

あなたがする必要があるのは、一歩下がって、データがどのようにアクセスされるかを確認することです。これは値を持つべき列ですか?これは、特定の場合にのみ値を持つ列ですか?これは頻繁に照会される列ですか?

于 2009-06-19T11:21:46.463 に答える