1

次の属性(列){ PKA、a1、a2 ...}を持つ親テーブルAと、次の属性を持つ子テーブルBがあります{FKA、b1、b2 ...} PKAはテーブルの主キー(自動インクリメント)ですA とテーブル B には主キーはありませんが、テーブル A の PKA 列を参照する外部キー列 FKA があります (1:n の関係)

エントリの追加: テーブル A にエントリを追加するとき ...PDO API の lastInsertId() を使用して挿入されたレコードを取得し、この値を使用してテーブル B に FKA を入力します。

問題: 1. エントリを削除しているときに、同様の方法で使用できる API 'lastDeleteId()' が見つかりませんでした。

さらに大きな問題: テーブル A で削除が発生した場合、設計上、削除コマンドは次のようになります。 DELETE from table A where a1 = . この a1 列は一意ではないため、DELETE コマンドはテーブル B からフラッシュする必要がある複数の PKA キーを返す可能性があります

注意事項:

  1. PDO API を使用しています
  2. MySQL テーブル (ここで検討中) は InnoDB です
  3. トランザクション モードで実行しています (beginTransaction() と commit()/rollback() の間の複数の SQL 呼び出し)
  4. CASCADE ON DELETE オプションを探していない

ご指摘ありがとうございます。

4

4 に答える 4

2

このクエリは、削除クエリの直後に使用することも、依存する親と連携して削除されなかった子に対してさかのぼって機能するバッチ クリーンアップ アプローチとして使用することもできます。

DELETE
    FROM  table_a
    WHERE a1 = ?;
SELECT    id
    FROM  table_b
    WHERE FKA NOT IN(SELECT id FROM table_a);

または、同じ WHERE 句を使用して削除クエリの直前に実行することもできます。

START TRANSACTION;
    SELECT    id
        FROM  table_b
        WHERE FKA NOT IN(
            SELECT id
                FROM table_a
                WHERE a1 = ?;
        );
    DELETE
        FROM  table_a
        WHERE a1 = ?;
COMMIT;

2 番目のアプローチは、トランザクションにラップして、他のスレッドがそれらのフィルターに一致する新しいデータを入力した可能性がある場合でも、選択時に一致した ID のみを削除するようにする必要があります。

編集 - アプローチの問題

使用している$pdo->beginTransaction()ときに 1 つのステートメントを発行SELECTし、ID をフェッチし、アプリケーション レベルでそれらを操作してからdeleteステートメントを発行すると、トランザクションがアクティブなままになり、一部のレコードがそのトランザクション内でロックされる可能性がありますFOR UPDATE。最初のselectステートメントおよび/またはあなたが高いISOLATION LEVELsを持っている場合。

アプリケーション層で時間のかかる操作を使用している場合、DB にアクティブなロックが長時間保持され、アプリケーションの同時接続容量が低下します。

私は、DB サーバーとの複数の通信セッションを避けることに長けています。だから$pdo->beginTransaction()最初から使わない。

「削除するIDを取得する」クエリを「削除されたレコードの処理に必要なすべてのデータを取得する」に拡張します。トランザクション内の 1 つの通信セッションでサーバーにクエリを送信するとSELECT、アプリケーションが受信するまでにデータがストレージから削除されていても、ステートメントの結果セットがアプリケーションに返されます。ペイロード。

于 2012-07-12T21:50:10.343 に答える
1

削除するレコードのレコード ID を選択し、それらを一時テーブルに配置します。次に、最初に子テーブルから削除し、次に親を削除します。これをトランザクションで実行すると、エラーが発生した場合にデータがロールバックされます。

于 2012-07-12T22:08:08.600 に答える
0

最も簡単な方法は、テーブル A の内容を一時テーブルにコピーし、削除を実行してから、一時テーブルの LEFT OUTER JOIN を更新されたテーブルに実行し、それを使用して行がなくなった行を見つけることだと思います。片方。

また、主キーを明示的に作成しない場合、InnoDB が内部で作成しませんか? InnoDB ストレージ エンジンには 1 つ必要だと思いました。

于 2012-07-12T21:49:51.497 に答える
0

データに一貫性がない可能性があるという考えに取り組んでみませんか。つまり、すでに削除されている pk への参照がある可能性があります。そして、fk が使用されるたびにチェックしてください。

次に、スケジュールされたタスクを追加して、fk が含まれていない場所からの選択 (select pk) を使用してチェックすることにより、レコードをクリーンアップします。

于 2012-07-13T01:14:27.763 に答える