6

idフィールド(主キー)に基づいてテーブルからいくつかの行を削除するクエリがあります。これは非常に単純なクエリです。

delete all from OUR_TABLE where ID in (123, 345, ...)

問題は、IDの数が膨大になる可能性があることです(例:70k)。そのため、クエリに長い時間がかかります。これを最適化する方法はありますか?(私たちはsybaseを使用しています-それが重要な場合)。

4

8 に答える 8

4

このようなステートメントを実行するには、次の2つの方法があります。

  1. 新しいテーブルを作成し、削除する行を除くすべてをコピーします。後でテーブルを入れ替える(alter table name ...)バカに聞こえても試してみることをお勧めします。一部のデータベースは、削除よりもコピーの方がはるかに高速です。

  2. テーブルを分割します。N個のテーブルを作成し、ビューを使用してそれらを1つに結合します。削除基準でグループ化されたさまざまなテーブルに行を並べ替えます。アイデアは、個々の行を削除するのではなく、テーブル全体を削除することです。

于 2009-02-23T10:59:53.173 に答える
3

70K個のアイテムを含むIN句を解析することが問題になるのではないかと思います。代わりに結合を使用して一時テーブルを試しましたか?

于 2009-02-23T10:55:40.813 に答える
3

これをバッチで実行することを検討してください。一度に 1000 件のレコードを実行するループは、すべてを実行する 1 つのクエリよりもはるかに高速である可能性があり、さらに、他のユーザーに対してテーブルを一気にロックアウトしたままにすることもありません。

カスケード削除 (および影響を受ける多くの外部キー テーブル) またはトリガーが関係している場合は、さらに小さなバッチで実行する必要がある場合があります。状況に最適な数を確認するには、実験する必要があります。100 のバッチで削除しなければならなかったテーブルと、50000 のバッチで削除しなければならなかったテーブルがありました (その場合、100 万のレコードを削除していたので幸運でした)。

しかし、いずれにしても、削除するキー値を一時テーブルに入れて、そこから削除します。

于 2009-02-23T14:35:23.577 に答える
2

パフォーマンスを使い果たしているものを見つけてください!

多くの場合、提供されているソリューションの1つを使用できます。ただし、他にも存在する可能性があります(Oracleの知識に基づいているため、他のデータベースでは状況が異なります。編集:sybaseについて言及したことを確認しました)。

  • そのテーブルに外部キーがありますか?参照IDがインデックスに登録されていることを確認します
  • そのテーブルにインデックスがありますか?削除前のドロップと削除後の再作成の方が速い場合があります。
  • 実行計画を確認してください。全表スキャンがより高速になる可能性があるインデックスを使用していますか?またはその逆ですか?ヒントが役立つかもしれません
  • 上記で提案したようにselectintonew_tableの代わりに、selectとしてテーブルを作成するとさらに高速になる可能性があります。

ただし、覚えておいてください。最初にパフォーマンスを使い果たしているものを見つけてください。

DDLステートメントを使用するときは、トランザクションとバックアップに与える可能性のある結果を理解し、受け入れるようにしてください。

于 2009-02-23T11:30:08.873 に答える
2

SybaseはIN句で70Kの引数を処理できますか?IN私が使用したすべてのデータベースには、句の引数の数に制限があります。たとえば、Oracleには約1000の制限があります。

IN句の代わりに副選択を作成できますか?これにより、SQLが短縮されます。たぶん、それはIN句のそのような多数の値に役立つ可能性があります。このようなもの:

  DELETE FROM OUR_TABLE WHERE ID IN 
        (SELECT ID FROM somewhere WHERE some_condition)

データベースモデルで許可されている場合は、データベースへの介入によって、多数のレコードの削除を高速化できます。ここにいくつかの戦略があります:

  1. インデックスを削除し、レコードを削除し、インデックスを再作成することで、処理を高速化できます。これにより、レコードの削除中にインデックスツリーのバランスを取り直す必要がなくなります。

    • テーブル上のすべてのインデックスを削除します
    • レコードを削除する
    • インデックスを再作成する
    • このテーブルとの関係が多い場合、deleteコマンドで整合性制約が破られないことが確実であれば、制約を無効にしてみてください。データベースが整合性をチェックしないため、削除ははるかに高速になります。削除後に制約を有効にします。
    • 整合性制約を無効にし、チェック制約を無効にします
    • レコードを削除する
    • 制約を有効にする
    • テーブルにトリガーがある場合、およびビジネスルールでそれが許可されている場合は、トリガーを無効にします。レコードを削除してから、トリガーを有効にします。

    • 最後に、他の提案どおりに実行します。削除されない行を含むテーブルのコピーを作成してから、元の行を削除し、コピーの名前を変更して、整合性制約がある場合は再作成します。

1、2、3の組み合わせを試してみます。それでもうまくいかない場合は、4です。すべてが遅い場合は、より大きなボックス、つまりより多くのメモリ、より高速なディスクを探します。

于 2009-02-23T11:12:35.453 に答える
1

また、一時テーブルがおそらく最良の解決策だと思います。

ただし、「delete from .. where ID in(select id from ...)」を実行した場合でも、大規模なクエリでは処理が遅くなる可能性があります。したがって、結合を使用して削除することをお勧めします。多くの人はその機能について知りません。

したがって、このサンプルテーブルを考えると:

    -- set up tables for this example
    if exists (select id from sysobjects where name = 'OurTable' and type = 'U')
        drop table OurTable
    go

    create table OurTable (ID integer primary key not null)
    go
    insert into OurTable (ID) values (1)
    insert into OurTable (ID) values (2)
    insert into OurTable (ID) values (3)
    insert into OurTable (ID) values (4)
    go

次に、削除コードを次のように記述できます。

    create table #IDsToDelete (ID integer not null)
    go
    insert into #IDsToDelete (ID) values (2)
    insert into #IDsToDelete (ID) values (3)
    go
    -- ... etc ...
    -- Now do the delete - notice that we aren't using 'from'
    -- in the usual place for this delete
    delete OurTable from #IDsToDelete
       where OurTable.ID = #IDsToDelete.ID
    go
    drop table #IDsToDelete
    go
    -- This returns only items 1 and 4
    select * from OurTable order by ID
    go
于 2011-03-09T17:04:41.657 に答える
1

「in」に渡す ID をテーブルと同じ順序で並べ替えてみてください。そうしないと、インデックスが格納されます。これにより、ディスク キャッシュでより多くのヒットが得られる場合があります。

削除する ID を、ID がメイン テーブルと同じ順序でソートされている一時テーブルに配置すると、データベースがメイン テーブルを簡単にスキャンできる場合があります。

データベース サーバー上のすべての CPU を使用するために、複数の接続を使用して接続を介して作業を実行することもできますが、最初にどのロックが解除されるかなどを考えてください。

于 2009-02-23T11:59:30.207 に答える
0

our_tableには削除カスケードに関する参照がありますか?

于 2009-02-23T10:58:17.407 に答える