0

インデックスを使用しない Hibernate によって生成されたクエリに問題があります。データベースへのアクセスは JTDS を使用して Java から行われ、サーバーのバージョンは SQL Server 2005の最新のサービス パックです。

フィールドは NULL 可能であり、特定のシナリオでは完全に NULL になる可能性がある外部キーです。列はクラスター化されていないインデックスを介してインデックス付けされますが、列が完全に NULL の場合、インデックスは使用されず、多数のフル テーブル スキャンが作成されます。そしてパフォーマンスの問題。

この状況は、次の SQL コードを含む標準のクエリ アナライザーを使用して確認することもできます。

テーブルとインデックスを作成する

CREATE TABLE [dbo].[TestNulls](
    [PK] [varchar](36) NOT NULL,
    [DATA] [varchar](36) NULL,
    [DATANULL] [varchar](36) NULL,
 CONSTRAINT [PK_TestNulls] PRIMARY KEY NONCLUSTERED
(
[PK] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,     
ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [IDX_DATA] ON [dbo].[TestNulls]
(
[DATA] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, 
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, 
ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IDX_DATANULL] ON [dbo].[TestNulls]
(
[DATANULL] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, 
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON,     
ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

newid 関数を使用して、いくつかのランダム データを入力します。

declare @i as int
set @i = 0
while (@i < 500000)
begin
  set nocount on

  insert into TestNulls values(NEWID(), NEWID(), null)
  insert into TestNulls values(NEWID(), null, null)
  insert into TestNulls values(NEWID(), null, null)           
  set @i = (@i + 1)
  set nocount on
end;

このクエリは、フル テーブル スキャンを実行します

declare @p varchar(36)
set @p = NEWID()
select PK, DATA, DATANULL from TestNulls
where DATANULL = @p

「and DATANULL IS NOT NULL」でクエリを完了すると、クエリはインデックスを使用するようになりました。

助けが必要:

  • JTDS/Hibernate の組み合わせにインデックスを使用させるにはどうすればよいですか (sendStringParametersAsUnicode はデフォルトで既に false に設定されています)。
  • null 許容フィールドを使用するすべての hibernate クエリに「and column is not null」を追加する方法はありますか?
  • この動作について何か説明はありますか?

よろしくマッシモ

4

2 に答える 2

1

1)NULL値は避けるべきだと思います。DEFAULTを使用して、いくつかの{00000-0000-000...}をNULL値として配置します。データ入力スクリプトが生成するnull値が多すぎるため、このフィールドの値の選択性は非常に低くなります。この場合、SQL Serverはスキャンしてからインデックスを使用することを選択すると思います(SQL Serverは自動的にインデックス自体を使用するか、使用しないかを選択します)。そしてそれは意味をなす。REALデータを分析する必要があります。いずれにせよ、何らかのインデックスを使用するように強制することができます。たとえば、SQLサーバーへのストアドプロシージャを作成して休止状態からクエリを実行するか、休止状態コマンドを使用してカスタムクエリを使用してデータを要求し(可能だと思います)、クエリにテーブルヒントを追加して、インデックスを使用して強制することができます。

INDEX(index_val [、... n]):

select PK, DATA, DATANULL from TestNulls WITH INDEX(IDX_DATANULL)

選択性は「行数」/「カーディナリティ」であるため、10Kの顧客がいて、すべての「女性」を検索する場合、検索で10K / 2 = 5K行が返されることを考慮する必要があります。したがって、非常に「悪い」です。 「選択性。

ラック。

于 2010-02-27T21:55:21.627 に答える
0

クラスター化されたインデックスのないテーブル (「ヒープ テーブル」と呼ばれます) を使用しています。これは、意味のあるクエリにはブックマーク ルックアップまたはフル テーブル スキャンが必要なため、一般に SELECT にはあまり効率的ではありません。

したがって、インデックスを使用するには、サーバーは次のことを行う必要があります。1) インデックスで指定された値を見つけて、対応する行 ID を取得します。2) ID で行を取得して、データを返します。

データの性質を考えると、オプティマイザはフル スキャンの方が効率的であると「考えます」。

試してみることをお勧めします:

  1. テーブルの統計を再構築します。統計が古いと、オプティマイザーが誤った決定を下す可能性があります。
  2. ヒントを介してインデックスの使用を強制します。実際のデータで本当に高速かどうかをテストすることを忘れないでください (オプティマイザーがたまたまあなたよりもよく知っている場合があります)。
  3. いくつかのデータを追加して、このクエリのカバリング インデックスを作成します (挿入/更新が多少遅くなるため、システムへの全体的な影響を考慮する必要があります)。

    CREATE INDEX IDX_DATANULL_FULL ON TestNulls (DATANULL) INCLUDE (PK, DATA)

于 2010-03-02T10:13:28.037 に答える