次のデータ構造があるとしましょう。
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 から、警告を発行せずにすべてのレコードを効率的に削除するにはどうすればよいですか?A
C
B
私が試したこと:
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 と検索バーの使い方を知っています。これが私が見つけたものです:
https://stackoverflow.com/questions/12275864/multiple-delete-not-working-with-inner-join
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
の文字になるので、この考えも好まれません。つまり、他に何もできない場合は、それが最後のオプションになります。