2

次のデータ構造があるとしましょう。

DROP TABLE IF EXISTS `A`;
DROP TABLE IF EXISTS `B`;
DROP TABLE IF EXISTS `C`;

CREATE TABLE IF NOT EXISTS `C` (
    `ID_C`
        INT UNSIGNED
        NOT NULL
        AUTO_INCREMENT,

    PRIMARY KEY (`ID_C`)
)
ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `B` (
    `ID_B`
        INT UNSIGNED
        NOT NULL
        AUTO_INCREMENT,

    `REF_C`
        INT UNSIGNED
        NOT NULL,

    PRIMARY KEY (`ID_B`),

    INDEX `FK_C` (`REF_C` ASC),

    CONSTRAINT `FK_C`
        FOREIGN KEY (`REF_C`)
        REFERENCES `C` (`ID_C`)
            ON DELETE CASCADE
            ON UPDATE CASCADE
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `A` (
    `ID_A`
        INT UNSIGNED
        NOT NULL
        AUTO_INCREMENT,

    `REF_B`
        INT UNSIGNED
        NOT NULL,

    PRIMARY KEY (`ID_A`),

    INDEX `FK_B` (`REF_B` ASC),

    CONSTRAINT `FK_B`
        FOREIGN KEY (`REF_B`)
        REFERENCES `B` (`ID_B`)
            ON DELETE CASCADE
            ON UPDATE CASCADE
) ENGINE=InnoDB;

INSERT INTO `C`
    (`ID_C`)
VALUES
    (NULL),
    (NULL);

INSERT INTO `B`
    (`ID_B`, `REF_C`)
VALUES
    (NULL, 1),
    (NULL, 1),
    (NULL, 2),
    (NULL, 2);

INSERT INTO `A`
    (`ID_A`, `REF_B`)
VALUES
    (NULL, 1),
    (NULL, 2),
    (NULL, 3),
    (NULL, 4);

テーブルBには 3000 を超えるレコードが含まれている可能性があります。約 600 のレコードが、テーブル内の異なる行を参照していますC。私のサーバーでは 2 つの設定が有効になっています。

SELECT
    @@SQL_SAFE_UPDATES as `safe mode`, -- result: 1
    @@LOG_BIN as `binary log`;         -- result: 1

質問: table を介して table のレコードに参照されている table から、警告を発行せずにすべてのレコードを効率的に削除するにはどうすればよいですか?ACB


私が試したこと:

DELETE
    `A`.*
FROM
    `A` INNER JOIN `B` ON `REF_B` = `ID_B`
WHERE
    `B`.`REF_C` = 1;

DBMS サーバーの問題safe_mode:

エラー コード: 1175。セーフ更新モードを使用していて、KEY 列を使用する WHERE なしでテーブルを更新しようとしました。セーフ モードを無効にするには、[設定] -> [SQL クエリ] でオプションを切り替えてから再接続してください。

B.エイリアスを削除しました:

DELETE
    `A`.*
FROM
    `A` INNER JOIN `B` ON `REF_B` = `ID_B`
WHERE
    `REF_C` = 1;

ええ、それは成功しましたが、私はこれを持っています:

影響を受ける 2 行、1 つの警告: 1592 BINLOG_FORMAT = STATEMENT であるため、ステートメント形式を使用して安全でないステートメントがバイナリ ログに書き込まれました。別のテーブルから選択した後に自動インクリメント列を含むテーブルに書き込むステートメントは安全ではありません。これは、行が取得される順序によって、どの行が (存在する場合) 書き込まれるかが決まるためです。この順序は予測できず、マスターとスレーブで異なる場合があります。

また、私は PRIMARY KEY の使用を強制しようとしていました:

DELETE
    `A`.*
FROM
    `A` INNER JOIN `B` ON `REF_B` = `ID_B`
WHERE
    `A`.`ID_A` > 0
    AND
    `REF_C` = 1;

しかし、それも役に立ちませんでした。サーバーに対して悪いことや悪いことをしていますか? どのアプローチが正しいですか?何か不足していますか?

前もって感謝します。どんな助けでも大歓迎です。


PS: Google と検索バーの使い方を知っています。これが私が見つけたものです:

  1. https://stackoverflow.com/questions/12275864/multiple-delete-not-working-with-inner-join

  2. http://tech-solutions4u.blogspot.ru/2012/09/mysql-multi-delete-issue-in-safe-mode.html

等々。試してみましたが、最終的には、「しばらくの間...」でもサーバー機能(私が設定したものではありません)を無効にするという考えは好きではありません。


編集:

私は、GROUP_CONCAT(ID_B)一時変数に保存し、その「スカラー」値で削除を実行する回避策があることを知っています:

SELECT GROUP_CONCAT(`ID_B`) INTO @tmp FROM `B` WHERE `REF_C` = 1;

DELETE FROM
    `A`
WHERE
    FIND_IN_SET(`REF_B`, @tmp)
    AND
    `ID_A` > 0;

しかし、それはおおよそ600 * 5 = 3000の文字になるので、この考えも好まれません。つまり、他に何もできない場合は、それが最後のオプションになります。

4

1 に答える 1