查询表时的 postgreSQL 性能



我是SQL新手,我不了解性能影响。SQL数据库似乎将所有内容存储在一个地方。这不意味着桌子会变得非常大,非常快吗?这不会损害性能吗?

示例 Stackoverflow 模型,但带有线程注释:

CREATE TABLE t_users (
   name varchar(80) primary key,
   email varchar(80)
);
CREATE TABLE t_posts (
   id varchar(80) primary key,
   userid varchar(80) references t_users(name),
   title varchar(80),
   description text,
   topic varchar(80),
   path text
);

这是一个有效的设计吗?每个用户的所有帖子都存储在同一个表中......因此,如果我想查询所有具有主题"编程"的评论,则需要查看每个帖子,甚至查看具有不同主题的帖子,因为它们都存储在同一个表中......这也意味着,如果我进行更复杂的查询,它们将呈指数级增长,磁盘上的表越大。将每个帖子拆分到一个新表中不是更好吗?

该设计是准有效的,但不完全有效:

  • 您的t_users最好是自动增量未签名整数 ID 列。(名称上的主键几乎总是一个坏主意。人们会改变名字。人们有相同的名字。甚至国家有时也会改变名称!数字几乎总是最好的选择!
  • 这样,您的t_posts就可以引用该用户 ID。现在,联接速度非常快。
  • 您甚至可以强制执行引用完整性:不存在的用户不能发布任何帖子。或者,当用户被删除时,帖子也会被删除。
  • 您的t_posts有一个 ID 主键列(好!(,但它是 varchar(坏!(。国际特更好。 BIGINT,如果你需要它。

您稍后会发现您的帖子可能有多个主题(stackoverflow"标签"(。不要将它们 CSV 放在 varchar 字段中。创建一个带有 ID、描述和链接表"posts_to_topic"的新表"主题",该表将每个帖子链接到一个或多个主题。

指标

您需要阅读的是索引。如果要查询所有具有主题"编程"的评论,通常会在"topic varchar(80("列上有一个索引。这个索引很小(把它看作是一个单独的表:它包含索引列和主键(,所以你的(R(DBMS可以非常快速地搜索它(树结构(并获取它需要的所有主键。然后,根据您选择的内容,DBMS 会向您发送以下信息:

  • 如果您只需要索引中已有的列,它可以从索引中获取所有内容。
  • 如果需要其他列,它现在只会实际访问t_posts表,并使用索引中的主键访问行。

简单化

我撒谎了。在最后一段中,我使一切变得简单得多。有一个优化器将查看查询并确定可以使用哪些索引。它将检查索引 - 取决于基数、表大小、它可能使用它的列,或者决定扫描表。如果表的行长度可变,则读取第 X 行比所有行具有相同长度(无 VARCHAR(时慢得多。所有这些都取决于您使用的(R(DBMS(或在MySQL中,甚至取决于哪个存储引擎(。

但是,请先阅读索引,了解内容,原因,然后再阅读方法。之后,您可以更深入地研究异常。

同一数据的多个表

这是一个经常犯的初学者错误,它们是双向的:

  • "我们可以将所有内容放在一个表中,如果我们添加一列"TYPE"并制作所有内容 varchar!">
  • "我们的数据库中只有 10000 个表,table_1、table_2等!">

阅读索引会告诉你为什么这在技术上是一个坏主意,但它在逻辑尺度上也不那么优雅:一个表意味着代表一个实体(Books。用户。职位。页面( - 拆分这些将导致一些非常丑陋的查询。如果你问某人为什么要这样做,原因通常是"为了速度",而他们的决策栏上的额外索引也会产生同样的效果。

一想:如果您为每个用户制作一个帖子标题,请编写列出 10 个最常用的主题以及每个主题有多少帖子的查询。您必须命名每个表!

你的问题的真正答案是"是"和"否"。 "是的",表格确实增长很快。"不"这通常不会影响性能。

尽管您可以将表视为扫描以查找结果的单个文件,但 SQL 的功能远不止于此。 几乎所有数据库都管理称为页表的东西,这意味着以下内容:

  • 一旦表被读取,如果它可以放入内存,它将保留在那里,直到它需要移出。 这大大加快了表上的进一步查询速度。
  • 加载页表通常从处理异步运行。

这两点本身很难(但并非不可能(在大多数编程语言中实现。 此外,SQL 还为您提供了索引和表分区,可以进一步加快单个表的处理速度。 最后,大多数版本的SQL都支持多个处理器/线程的几乎所有功能。

合并来自多个表的结果或聚合结果时,数据库在执行联接和聚合的算法方面需要花费大量人力年的努力。 在这种情况下,您不太可能做得更好。

而且,这些功能不涉及关系数据库的许多其他功能,例如强制数据一致性、备份和还原数据、保证修改等。

至于您的表架构,您似乎正在开始并且很好。 通常,我建议主键以表命名并且是整数。 然后,您的第一个表将是:

CREATE TABLE users (
    UserId int primary key,
    name varchar(80),
    email varchar(80)
); 

第二个表中的 UserId 被声明为 int。 作为为什么这更好的提示,用户可能希望不时更改其名称。

每个帖子拆分到一个新表中不是更好吗?

不。

如果您的帖子位于不同的表中,则必须查询数百甚至数千个不同的表才能找到所有数据。

更不用说,除了数据(无论数据在哪个表中,其大小都相同(之外,您还有表本身的开销。

最新更新