1

除其他外,我有三个表accountaddressaccount_address。该account_address表有一个account_id和一个address_id。这是您的标准多对多关系。

我有一个令人困惑的情况,我有一个account_address指向account不存在的记录。由于我有一个account_address.account_id指向的外键account,这应该不会发生,对吧?

现在让我证明这应该是不可能的事情正在发生。首先,我将向您展示我的表定义:

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 附加到六个不同的帐户(一个帐户,有趣的是与地址具有相同的 id)。但是看看这个:

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

没有结果!我的 DBMS 不应该在某个时候告诉我我的外键约束失败了吗?!

我只看到两种可能性:

  1. 我误解了我所看到的
  2. 我的 DBMS 在根本上行为不端

我当然希望 #1 是这种情况,但我不知道我可能会误解什么。这对我来说是一个最高级别的谜。任何想法将不胜感激。

4

2 回答 2

1

A constraint will stop any actions to do something 'evil', but will not retroactivly make sure everything is allright. You can, as many import scripts do because of the order in which stuff happens, set the checking of these constraints to 0.

So if for some reason the information is incorrect, this situation can occur. Then your DBMS is not misbehaving, and you're also not misinterpreting.

So i'd go for option 3: Some import or insert is misbehaving, possibly using "set foreign_key_checks = 0". Or it is old data.

(from the manual:

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 检查允许导入继续。

您丢失的记录可能在禁用密钥检查期间被删除。要测试密钥现在是否正常工作,请添加几条相关记录并删除一条,由于 FK 上的“无操作”设置,这应该会失败。如果它继续,那么要么你不在 InnoDB 上(也许它被禁用并且 mysql 正在默默地转换为 MyISAM),关键检查被关闭(检查那个服务器变量),或者你的服务器真的有问题。

于 2011-02-11T15:51:13.547 回答