多列vs少表-性能明智


12

是的,我知道数据规范化应该是我的首要任务。

  1. 我有一个表,65列存储与列车辆数据:used_vehiclecolordoorsmileageprice等等,总共65。
  2. 现在,我可以除以和有一个Vehicle表,VehicleInteriorVehicleExteriorVehicleTechnicalVehicleExtra(全一到一个与主Vehicle表)。

假设我有大约500万行(车辆)。

SELECT带有WHERE子句的情况下:搜索效果会更好(两种情况至少都在上索引IDs):

  1. Vehicle 65列的表格或
  2. Vehicle表与JOINS其他四个表(均具有500万行)一起返回与Vehicle?相关的所有数据

(根据数据库引擎,考虑PostgreSQL和/或MySQL)。

真的很欣赏您以前的经验中得到的任何详细见解吗?


1
进行此操作(垂直分区)的一个原因是,如果您有查询处理来自的列的VehicleInterior查询,其他查询仅处理来自的列的查询VehicleTechnical,等等。或者如果有很多行/车辆完全没有(例如)有关此信息,VehicleExtra那么不是有很多空值在一个表中的多个行,你必须在表中的其他行,且行中VehicleExtra
ypercubeᵀᴹ

Answers:


14

假设我们正在讨论所有表之间的1:1关系。

整体存储实际上总是(基本上)与便宜的单个表,而不是多个表在1:1的关系。每行有28个字节的开销,通常还有几个字节用于额外的填充。并且您需要在每个表中存储PK列。并且在每个这些列上都有一个单独的(冗余)索引。大小对于性能至关重要。

如果大多数行中的许多列为NULL,则甚至是这样,因为NULL存储非常便宜

检索所有列时,单个表的速度明显快于连接在一起的5个表的速度。这也要简单得多。如果不是所有表中都没有所有行,则五个表可能很难连接。使用WHERE针对单个表的条件,可以很容易地将其他表附加到LEFT JOIN。如果您有多个表的谓词,那么它就不那么简单了……

垂直分区 仍然可以提高某些查询的性能。例如,如果您有90%的查询在65个可用查询中检索到相同的5列,那么对于只包含这5列的表来说,这样做会更快。

OTOH,您也许可以通过“覆盖”索引来满足对少数选定列的此类查询,从而允许仅索引扫描

垂直分区的另一种选择:如果您仅在几列上进行大量更新,而其余​​几乎不变。在这种情况下,拆分行可能会便宜得多,因为Postgres会为每次更新编写新的行版本。离线存储大值(“ TOASTed”)有例外。更多细节:

这实际上取决于整体情况。如有疑问,请使用拥有单个桌子的简单解决方案,尤其是当它很好地描述现实时:在您的示例中,这些都是汽车的属性,并且在一起就有意义。


如果不进行更新,则很少进行更新,而对大多数搜索结果列表的主要列(车辆详细信息页)和主要信息(很少的列)进行选择,实际上,最好的解决方案可能是两个表:一个包含主要信息的表(很少的列) )和其他表格以及其余的列。所以在这种情况下,您对sql联接的处理方式是说500万行-性能明智的做法?顺便说一句BTW感谢您的详尽努力
Urim Kurtishi 2015年

1
@octavius:在列上具有列索引以允许对结果列表进行仅索引扫描的单个表可能是最佳途径。(请注意,btree索引中的列顺序很重要。)连接并没有那么昂贵,但是如果没有连接,连接仍然会更快。多个表的增加的存储大小和数据的散布可能会带来更大的影响(每个查询要读取更多的数据页)。
Erwin Brandstetter 2015年

1
我同意Erwins的评论,答案将取决于实际情况或实际使用情况。如果您发现90%的查询是在数据的一小部分上,而性能绝对是最重要的,则可能有理由证明将额外的精力分成许多表是合理的。我个人将尝试保持数据模型简单。还有,多快才足够快?您为节省最后一毫秒付出了多少努力?您是否尝试过模拟任何数据并进行任何测试?
Swears-a-lot爵士,2015年

您在回答中提到的@ErwinBrandstetter关系是1:1。1:N关系船呢?
苗条的

对于1:N关系,无论如何都需要两个单独的表。除非您将多行填入数组或文档类型。然后,这取决于。无论如何,此处概述的原理均适用。您的访问模式和索引策略可以有所作为。提出一个新问题,是否要更具体。
Erwin Brandstetter '18

0

在单个表上进行选择应该总是更快。一旦找到您的车辆,您便已经拥有所有详细信息。

但是,您将失去标准化的效率。例如,如果一辆汽车有许多具有不同选项的模型。

这是所有汽车的参考分贝吗?还是二手车清单?是否会有许多具有相同选项的相同品牌/型号的示例?

编辑:我应该把我的答案限定为通用rdbms而不是特定于postgres。我遵照@Erwin针对postgres的详细答案


2
“在单个表上进行选择应该总是更快。” 为什么?
ypercubeᵀᴹ

Vehiclemake和Vehiclemodel是不同的表,因此Vehicle表具有Vehiclemake和Vehiclemodel的外键。我不认为规范化在这里是个问题。我知道在单个表上进行选择会更快,但是我们有不同的情况,与多列的行如何影响性能等等,与少列的表(但很少有表-其中有5个具有联接)的表相比
Urim Kurtishi

抱歉,我错过了品牌和型号已经分开的问题。简短的版本是联接需要数据库引擎的努力。如果使用单个表/行,则将所有内容都置于一个选择中,这将减少db引擎的I / O和开销。
Swears-a-lot爵士,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.