【问题标题】:Which database design gives better performance?哪种数据库设计提供更好的性能?
【发布时间】:2014-06-12 19:41:39
【问题描述】:

我想select 检索person 并进一步进行一些插入、删除和更新。

如果我想检索住在Brazil 的person,最好的方法是什么?

在表person中创建2个外键city和country:

Person(id, name, profession, **id_country**, **id_city**)   
cities (id, city, **id_country**)  
countries (id, country) 

或者只是表person中cities的一个外键和表cities中的另一个外键county

Person(id, name, profession, **id_city**)   
cities (id, city, **id_country**)   
countries (id, country)

或者像第一个选项一样制作一个视图?

对于插入、删除和更新数据,它们仍然是最好的表吗?性能没有区别?我也很困惑,什么会影响模式中的性能?

【问题讨论】:

  • 你如何衡量“最佳”?
  • 在性能方面。和其他标准,如果他们可以帮助我
  • 你想做什么?插入?删除?更新?具体查询?
  • 我现在只想进行一些搜索查询select。如果你想给出插入、删除和更新的所有情况。
  • 性能是检索或修改数据的命令的属性,而不是数据存储方式的属性。您应该通过您希望执行良好的查询示例以及对各种表大小的估计来阐明您的问题。

标签: sql database-design database-performance database-normalization


【解决方案1】:

一般而言,数据完整性比性能更重要,因此只有在您对代表性数据量执行测量并且结果表明强烈需要更好的性能。更常见的情况是,规范化的模式会执行得很好,特别是如果您的物理设计正确(例如索引)。

在这种特殊情况下,我的预感是第二个(标准化)设计可以正常工作。

话虽如此,查询的最有效设计可能是:“哪些人住在给定的国家”看起来像这样:

然后cluster PK 上的人。这样,属于同一 COUNTRY_ID 的所有人员都物理上靠近一起存储在数据库中,从而显着减少上述查询的 I/O2。

另一方面,您不再使用简单的自动增量机制来生成您的 CITY_NO 和 PERSON_NO,PERSON 上的二级索引很昂贵,因为集群会导致 other 查询变慢等。所以,这并不比您的第二个设计绝对“更好”,它们只是具有不同的优势/劣势,您必须决定在您的特定情况下哪个是更好的权衡。


1 这可以防止数据库“自卫”自己免受不良数据的影响。在您的情况下,第一个(非规范化)设计将允许一个人引用一个不包含同一个人引用的城市的国家/地区。

2 I/O 往往是大多数查询的最大成本。

【讨论】:

  • 为什么不能为这些列使用自动生成值?我错过了他们呢?诚然会有“差距”,但它们仍会按密钥的主要元素分组,这意味着同一国家/城市的人们仍将被分组。
  • 但是如果我让我的数据库标准化并创建视图?这是最好的方法吗?创建视图会影响性能吗?
  • @Clockwork-Muse 是的,你可以这样做,但这些“间隙”要么浪费存储空间(如果你的 DBMS 有可变宽度表示的整数),要么让你更快地用完可用值(以固定宽度表示)。
  • @Youssef 除非这些视图被具体化,否则仅视图不会影响性能。视图只是将查询存储在数据库本身中的一种方便方式,一般来说与(适当准备的)查询没有不同的性能。但不要相信我的话。说真的,不要。始终衡量自己。
  • 好的,所以你正在为每个城市/国家组合进行增量,对吧?如果一个城市搬到另一个国家会发生什么?还是一个人去不同的城市?以及您打算如何生成这些 id?
【解决方案2】:

这个问题和你昨天做的很相似:

Create many tables or just one

答案也类似——这取决于你想要达到的目标。两种解决方案都可以工作,并且都各有利弊,应该根据具体情况进行一些权衡分析。在这种情况下无法回答您的问题。

我在两个版本中看到的唯一区别是 Person 表中的外键 id_country:

人员(id、姓名、职业、****id_country****、id_city)
城市 (id, city, id_country)
国家(id,国家)

问题是“我们需要它吗?”

那么,两种解决方案的优缺点:

1.解决方案:使用 id_contry:

  • 优点:更容易根据土地检索人员(更简单的查询)和更好的查询性能
  • 缺点:更复杂的底层 DB 和更多冗余,在 DB 中减少不一致的可能性更大,更新更困难

2。解决方案:没有 id_country:

  • 优点:模型更简单、更简洁、无冗余、更易于维护
  • 缺点:基于土地的 Person 检索性能较慢和更复杂的查询(更简单的查询)

因此,第一种解决方案有效地为您提供了更简单的查询结构和更好的按国家/地区检索人员的性能(您想要的),但它有其成本(请参阅优缺点)。另一方面,务实的思维认为乡村-城市数据相当稳定,不经常变化,这一事实支持第一种解决方案。

如果您可以忍受这种非规范化和轻微不一致的可能性,您可以采用第一种解决方案。

【讨论】:

  • 但是如果我让我的数据库标准化并创建视图?这是最好的方法吗?创建视图会影响性能吗?
【解决方案3】:

取决于您想要实现的目标。在这两种情况下,您都在输入冗余数据。这称为非规范化。非规范化的第二个示例称为“短路密钥”:

Person(id, name, profession, **id_city**)   
cities (id, city, **id_country**)   
countries (id, country)

这样的结果可以在查询执行时产生更少的表连接。第一个例子叫做“星型模式”:

Person(id, name, profession, **id_country**, **id_city**)   
cities (id, city, **id_country**)  
countries (id, country)

星型模式由一个或多个引用任意数量维度表的事实表组成。星型模式连接逻辑通常比从高度规范化的事务模式中检索数据所需的连接逻辑更简单。这个例子在数据仓库数据库设计中很常见。

在任何情况下都不会影响性能,您可以选择其中一种来检索您需要的数据。

【讨论】:

  • 感谢您的解释,但是对于插入、删除和更新数据,它们仍然相同吗?性能上没有区别?我也很困惑什么会影响架构中的性能?
  • 对于插入、删除和更新数据,应该在表上定义一个触发器。防止所谓的孤立数据。而插入、删除和更新冗余数据始终是一个性能问题。您必须在选择和编写联接是更简单的方法还是更快地插入、删除和更新之间做出决定。
  • 但是如果我让我的数据库标准化并创建视图?这是最好的方法吗?创建视图会影响性能吗?
  • 是的,在某些情况下,视图可以更新性能,具体取决于您创建的视图类型。
  • 您可以创建两个解决方案并发布问题租用,两者哪个性能更好,数据库设计和表格中的一些数据,然后我们将看到。 :)
【解决方案4】:

(您的原始帖子没有解决性能而是规范化,但它有很多编辑并引入了“性能”,可能是因为您的 cmets 提到了它。)

关系模型的一个要点是通用查询,具有自动化实现和自动化优化。 最初忽略性能。只需做一个简单的设计。(在此之前,您必须学习如何制作。)ID 与性能无关。归一化与性能有关,但因为你应该首先归一化到 5NF,所以这是没有实际意义的。外键与性能有关,但由于您应该为完整性定义它们,因此它们在性能中的作用是没有实际意义的。适当的设计可以在以后进行调整。

无论如何,性能是各种因素的权衡,如果您不知道自己想做什么样的事情,那么讨论性能是没有意义的。 (或者,如果您甚至不知道这些东西是什么。)此外,必须测量与性能相关的属性,甚至认为手动优化干预是合适的。 (同样,您必须了解这些因素到底是什么。)

当性能因为特定应用程序进行特定的查询或更新模式而成为一个明显的问题时,您可以解决性能问题。首先通过索引和视图使这些模式表现更好——总是以牺牲其他模式为代价。

您提到(和未提及)的事物种类以及您提到它们的方式表明您对性能及其与设计的关系存在误解。此外,您对关系结构、查询和 DBMS 的理解极低。在您了解有关基本设计的更多信息之前,您获得的关于性能偏差的任何建议都是错误的。所以忘记性能吧。 对性能产生不利影响的主要因素是过早地担心性能会妨碍简单的设计。

最简单的设计是

person(id, name, profession, city, country)
    -- person [id] is named [name] and practises [profession] in [city], [country]  
city (name, country) -- [name] uniquely names a city within country [country]
country (name) -- [name] uniquely names a country

这有一定的键和外键,只要声明它们——这与性能无关。它在 5NF 中。

您可能会明白,下面的设计(您可以添加相关的约束)可能比之前的设计更适合您——这与性能无关。然后您可以转到它并将以前的表作为视图提供给老用户——这与性能无关。

person(id, name, profession, id_city)
    -- person [id] is named [name] and practises [profession] in [id_city]  
city (id, name, id_country) -- city [id] is named [name] and is in country [id_country]
country (id, name) -- country [id] is named [name]

这里的 id_country 会违反 5NF,因为它在功能上依赖于非键 id_city。

【讨论】:

  • 现实生活中,同一个国家可能有多个同名城市。
  • @BrankoDimitrijevic Aw,你破坏了惊喜。
猜你喜欢
  • 2013-08-15
  • 2018-06-27
  • 1970-01-01
  • 2013-10-07
  • 2018-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多