我是一个非常小的团队(3-4人)的数据库管理员的工作,虽然我知道如何较好地执行SQL查询并了解编程效率的基本知识,但我在数据库架构的思考领域仍然是个新手。
我注意到了前面的管理员,构建了一个奇怪的模式,我还在试图找出它的好处。因为他在DB体系结构方面比我更有经验,所以肯定有一些积极的方面。不幸的是,他已经不能再问他的动机了。
本质上,每当有一个字符列的值经常重复(例如,表中的salesman_name )时,该字符列将被索引(salesman_id)所取代,充当另一个表的外键。第二个表将只包含外键(salesman_id)和唯一字符值(salesman_name)列表。没有其他表使用此字符列。
为什么要这么做?
如果有其他表链接到salesman_name,那么我可以理解这种做法,所以salesman_name的更新可以在一个地方完成。在节省磁盘空间方面,我也能理解,因为每一行复制的字节较少。然而,我们的sales表“只有”500万行,即使在csv格式中,它的大小也小于1Gb。虽然它保存在磁盘上,但每当我们想要查看成熟的sales表时,它都需要一个Join。这种情况经常发生,以至于以前的管理员甚至已经用这个联接设置了一个视图。但是,为什么以后要单独分开来团结呢?还有其他明显的理由来分离我丢失的重复数据吗?
发布于 2022-12-12 09:17:39
大多数关系数据库使用分页存储。对于DBMS来说,IO的单位是1页。每个页面通常包含多个行。每一行都完全适合于一个页面。
当查询需要行时,它的整个页面都会被读取。该页面上的所有其他行都可以用于其他查询,而无需支付进一步的IO成本。因此,页面上的行越多,IO就越少,系统运行得越快。
除此之外还有许多其他的技术和实现,但上面提到了许多典型的情况。
在页面上容纳更多行的一种方法是使每一行都更短。替换名称(15-40字节?)使用int (4个字节)将有助于解决这个问题。int到string映射将是一个单独的表。由于相对很少有不同的字符串值,这个映射表将很小。总的来说,IO将出现净减少。
您可以将此视为字典压缩的一种形式。可以说,它也更加正常化,因为纠正错误将更新一行中的一列,避免数据不一致的风险。我不太相信,把一个天然的钥匙换成一个代孕钥匙,就算是正常化了。
是的,必须有联接才能返回完整的销售行。要连接的数据更可能在内存中,DBMS被优化为join,因此它可能比等效的磁盘访问更快。
如果所有表都能很好地放入RAM中,并有足够的剩余时间执行查询,那么空间最小化是不值得的。也许当系统开始运行时,它运行在一个带有500 on磁盘的286上,而这是值得的吗?也许这是一种习惯,设计师从过去的经验,从来没有想过要质疑。
发布于 2022-12-13 09:32:28
..。每当出现字符列whose值时,通常都会重复(例如,销售表中的salesman_name ),该字符列将被索引(salesman_id)取代,充当另一个表的外键。第二个表将只包含外键(salesman_id)和唯一字符值(salesman_name)列表。没有其他表使用此字符列。为什么要这么做?
一个单词答案-规范化您有一个推销员的名字副本,保存在单独的表(a.k.a )中。“真理的单一来源”)。正如您所说的,您将拥有该Salesman的许多销售记录,其中每个记录都只有Salesman记录的标识符。这正是构建关系数据库的方式。
其他原因:
一个推销员可以“存在”没有任何销售。新起步者,谁还没有出售任何东西,必须“在系统中”以某种方式。您可以添加推销员记录而不影响其他任何内容。任何可以“独立”存在的东西都需要它自己的表格。
人们改名了。如果您在很多销售记录中嵌入了实际名称,那么更改所有这些记录对于您的数据库来说可能是一项巨大的操作--大量事务日志、磁盘写入等等,这是很昂贵的。在数据正常的情况下,您只需要在一个记录中更改一个字段。
随着时间的推移,您可能希望在该表中存储的不仅仅是推销员的名字。有了这样的“拆分”,在Salesman表中添加额外的列本身就很简单。没有它,你将不得不“膨胀”销售表,这可能会回来,并“咬”你以新的和意想不到的方式。
https://dba.stackexchange.com/questions/320782
复制相似问题