编辑
如果一张图片只属于二十张桌子中的一张,那么这种设计可能会奏效:
People (PersonId, Name)
Places (PlaceId, Name)
Dogs (DogId, Breed)
Doors (DoorId, Height, Width)
Images (ImageId, ImageBinary, OwnerId, OwnerTable)
其中 OwnerTable 是 OwnerId 所属表的名称或代码。
这将在图像表中为您节省 20 个 FK,或 20 个关联表。然后,在连接中,您将指定 OwnerTable,具体取决于您要连接的表。
您需要为 Id 使用可转换类型(例如,TINYINT、SMALLINT 和 INT),最好是为所有类型使用一种类型(例如,INT),并且您必须自己通过触发器或其他代码来管理引用完整性。
/编辑
您需要 5 个表,而不是 3 个:
People (PersonId, Name)
Places (PlaceId, Name)
Images (ImageId, ImageBinary)
ImagesPeople (ImageId, PersonId)
ImagesPlaces (ImageId, PlaceId)
您可以随意调用这些字段。People.Id、ImagesPeople.PersonId 等。
但是你不能做的是这样的:
People (PersonId, Name)
Places (PlaceId, Name)
Images (ImageId, ImageBinary, PlaceOrPersonId)
好吧,你可以,但是数据库不会帮助你强制执行关系,或者告诉你 FK 属于哪个表。你怎么知道的?有一些 hackish 变通办法,例如错开 id 增量、向图像添加类型列或使用 GUID。
或者:
Things (ThingId PK, Type)
People (ThingId PK/FK, Name, Age)
Places (ThingId PK/FK, Name, LatLon)
Images (ImageId PK, ImageBinary, ThingId FK)
您还可以将图像作为“事物”。有时你会看到这样的设计。它确实为您提供了参照完整性,但不提供类型排他性。您可以在人物、地点和图像中拥有相同的 ThingId,而数据库不会在意。您必须自己编写该规则。
编辑:根据 Cylon Cat 的建议,场景 4:
People (PersonId, Name)
Places (PlaceId, Name)
PeopleImages (PeopleImageId, ImageBinary)
PlaceImages (PlaceImageId, ImageBinary)
在这里,图像由一个人或一个地方独家拥有。与版本 2 类似,但具有声明的外键。与 5 表设计相比,它可能具有一些性能优势,因为需要的连接更少。你失去了“图像”作为一个独特的实体,取而代之的是“人物图像”和“地方图像”。