【发布时间】:2023-03-30 08:14:02
【问题描述】:
采用以下类型的表格设计:
http://www.martinfowler.com/eaaCatalog/classTableInheritance.html
让我们使用以下架构作为示例:
CREATE TABLE `fruit` (
`id` int(10) UNSIGNED NOT NULL,
`type` tinyint(3) UNSIGNED NOT NULL,
`purchase_date` DATETIME NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `apple` (
`fruit_id` int(10) UNSIGNED NOT NULL,
`is_macintosh` tinyint(1) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `orange` (
`fruit_id` int(10) UNSIGNED NOT NULL,
`peel_thickness_mm` decimal(4,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `fruit`
ADD PRIMARY KEY (`id`);
ALTER TABLE `apple`
ADD KEY `fruit_id` (`fruit_id`);
ALTER TABLE `orange`
ADD KEY `fruit_id` (`fruit_id`);
ALTER TABLE `fruit`
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `apple`
ADD CONSTRAINT `apple_ibfk_1` FOREIGN KEY (`fruit_id`) REFERENCES `fruit` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `orange`
ADD CONSTRAINT `orange_ibfk_1` FOREIGN KEY (`fruit_id`) REFERENCES `fruit` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
这里,'apples' 和 'oranges' 是 'fruit' 的类型,并且具有独特的属性,这就是为什么它们被分割到自己的表格中。
问题是,从性能的角度来看,在执行SELECT * FROM fruit 查询时,最好:
a) 在每个类型的表上执行LEFT OUTER JOIN,即apple 和orange(实际上,我们可能要处理几十种水果类型)
b) 跳过连接,稍后对应用程序逻辑中的每个 fruit 行执行单独的查询,因此对于 apple 类型的 fruit 行,SELECT * FROM apple WHERE fruit_id=...?
编辑: 至于具体的场景,我就不赘述了,但这里的实际应用是一个通知系统,它会在某些事件发生时生成通知。每种事件类型都有不同的通知类型,每种通知类型都存储该事件类型独有的属性。这是在一个有大量用户活动的网站上,因此最终会有数百万行通知。
【问题讨论】:
-
这不会让您满意,但这里是:工作较少的查询将执行得更好。由于您没有数据,因此无法确定哪个更快。 TL;DR:信息不足,无法得出有效结论。
-
但一般规则是,连接通常比在循环中执行大量单独的查询要好。
-
考虑使用单个属性值表,而不是为每种水果创建大量单独的表。
-
仅在需要时获取所需数据。因此,如果您需要在显示水果数据的同时显示苹果、橙子的从属数据,则将其全部放在左连接上。
-
我用我的特定应用程序的一些细节更新了这个问题。 @Barmar,我对
LEFT OUTER JOINs 的担忧是,由于其中只有一个会在键上匹配,因此会导致大量浪费的索引搜索。您是否认为每行的额外查询比每行约 10 次丢失的索引查找更昂贵?我曾考虑使用单个表,但由于所有空的保留数据列,我认为这可能会浪费空间。
标签: mysql performance oop