1

、 、 の 3 つのテーブルaccountaddressありaccount_addressます。account_addressテーブルにはとaccount_idがありaddress_idます。これは、標準的な多対多の関係です。

存在しないaccount_addressを指すレコードがあるという困惑した状況があります。を指しaccountている外部キーがあるので、これは起こりえないはずですよね?account_address.account_idaccount

では、この不可能であるべきことが起こっていることを証明しましょう。まず、テーブル定義を示します。

CREATE TABLE `account_address` (    
  `id` bigint(20) NOT NULL AUTO_INCREMENT,    
  `account_id` bigint(20) NOT NULL,    
  `address_id` bigint(20) NOT NULL,   
  `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',    
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',    
  PRIMARY KEY (`id`),    
  KEY `fk_account_address_account_id` (`account_id`),    
  KEY `fk_account_address_address_id` (`address_id`),   
  KEY `index_account_address_account_id` (`account_id`) USING BTREE,    
  KEY `index_account_address_address_id` (`address_id`) USING BTREE,    
  CONSTRAINT `fk_account_address_account_id` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,    
  CONSTRAINT `fk_account_address_address_id` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION    
) ENGINE=InnoDB AUTO_INCREMENT=697173 DEFAULT CHARSET=latin1

見る?FOREIGN KEY (account_id) REFERENCES account (id).

次に、その制約が失敗したことを示すいくつかのクエリを示します。

select aa.account_id
from account_address aa
where aa.address_id = 15116

そのクエリにより、次の結果が得られます。

15116
37033
62325
71857
93774
119066

したがって、どうやらアドレス 15116 は 6 つの異なるアカウント (興味深いことに、アドレスと同じ ID を持つ 1 つのアカウント) に関連付けられています。しかし、これをチェックしてください:

select * from account where id in (15116, 37033, 62325, 71857, 93774, 119066)

結果がありません!ある時点で、外部キー制約が失敗したことを DBMS が教えてくれるはずではありませんか?!

私は2つの可能性しか考えていません:

  1. 見ているものを誤解している
  2. 私の DBMS は根本的な方法で誤動作しています

#1が当てはまることを願っていますが、何を誤解している可能性があるのか​​ わかりません. それは私にとって最高のミステリーです。どんな考えでも大歓迎です。

4

2 に答える 2

1

制約は、何か「悪」を行うアクションを停止しますが、すべてが問題ないことをさかのぼって確認するわけではありません。多くのインポート スクリプトと同様に、物事が起こる順序のために、これらの制約のチェックを 0 に設定できます。

したがって、何らかの理由で情報が正しくない場合、このような状況が発生する可能性があります。そうすれば、あなたの DBMS は間違った振る舞いをしておらず、あなたも誤解していません。

だから私はオプション3に行きます:おそらく「setforeign_key_checks = 0」を使用して、一部のインポートまたは挿入が誤動作しています。もしくは古いデータです。

(マニュアルから:

mysql> SET foreign_key_checks = 0;
mysql> SOURCE dump_file_name;
mysql> SET foreign_key_checks = 1;

)

于 2011-02-11T15:34:11.307 に答える
0

MySQL には、外部キー チェックを無効にするサーバー変数がありますset foreign_key_checks=0。これは、まだロードされていないダンプの「後で」テーブルを指している FK がテーブルにある可能性があるダンプ ファイルをインポートする場合などに使用されます。通常、これはインポートを強制終了しますが、データは問題ありません。FK チェックを無効にすると、インポートを続行できます。

キー チェックが無効になっている間に、不足しているレコードが削除された可能性があります。キーが正しく機能しているかどうかをテストするには、いくつかの関連レコードを追加して 1 つ削除します。これは、FK の「アクションなし」設定のために失敗するはずです。続行する場合は、InnoDB を使用していないか (無効になっており、mysql が静かに MyISAM に変換している可能性があります)、キー チェックがオフになっている (サーバー変数を確認してください) か、サーバーに何か問題があります。

于 2011-02-11T15:51:13.547 に答える