【问题标题】:How to set the right indexes on a sql table?如何在 sql 表上设置正确的索引?
【发布时间】:2014-12-18 09:52:38
【问题描述】:

如何确定值得在sql 表上设置的索引?

以以下为例:

select * 
from products 
where name = 'car' 
  and type = 'vehicle' 
  and availability > 3 
  and insertion_date > '2015-10-10' 
order by price asc 
limit 1

想象一个有几百万个条目的数据库。 如果我为WHEREORDER BY 子句中出现的所有属性的组合设置索引,会有好处吗?

例如:

create index i_my_idx on products
   (name, type, availability, insertion_date, price)

【问题讨论】:

  • 无法使用单个示例查询来确定正确的索引。您需要对所有个查询有一个概览,这些查询是最频繁和最重要的。它还取决于您的其余设置。有多少写操作(具体是什么)?数据分布、基数、资源等。你不能说“sql table”。 SQL 是查询语言,表就是表,如果你愿意的话,就是“数据库表”。
  • @a_horse_with_no_name:其实只要索引的所有列有相等条件,根本哪一列都没有关系先来。 See this related answer on DBA with a test case. 在这种情况下,我们有范围和平等。 Equality should go first. 所以显示的索引中列的顺序是好的。
  • @a_horse_with_no_name 感谢您提供详细的 cmets,我明白了。因此,让我们再举一个航班示例:可能最好为departure_airportarrival_airport 添加索引。想象一下,我得到一个包含 1k 个条目的结果集。如果在departure_date 上放置例如索引,会不会有更多好处,而在特定日期可能只有 10 个条目?
  • 有关基本经验法则,请阅读introduction in the manualthis related answer

标签: sql database postgresql


【解决方案1】:

在决定要索引哪些列时,有一些经验法则很有用:

  1. 确保主键上有唯一索引 - 当您在包括 postgresql 在内的大多数 RDBMS 中指定 PK 时,这会自动完成。
  2. 为每个外键添加索引。当您指定 FK 而不是在 postgresql 中时,它们会在某些 RDBMS 中自动创建。
  3. 如果 PK 是复合键,请考虑在组成 PK 的每个 FK 上添加索引(第一个除外,它包含在 PK 索引中)。与 2 中一样,一些 RDBMS(例如带有 ISAM 的 MySQL)在指定 FK 时会自动添加这些索引。

通常但并非总是如此,查询中的表连接将是 PF 到 FK,并且通过在两个键上都有索引,RDBMS 的查询优化器可以灵活地确定最佳计划以获得最大性能。但这并不总是最好的,有经验的程序员通常会为数据库查询格式化 SQL 以影响执行计划以获得最佳性能,或者决定省略他们知道不需要的索引。值得注意的是,在一个 RDBMS 上最佳的 SQL 查询不一定在另一个 RDBMS 上或在未来版本的数据库服务器上或随着数据库的增长而最佳。后者很重要,因为在一些 RDBMS(如 postgres 和 Oracle)中,查询执行计划取决于表中的数据(这称为基于成本的优化)。

一旦您解决了这些问题,就可以归结为经验和对数据的了解,更重要的是,如何访问数据。

通常,您会寻找最适合过滤数据的列。在您上面的查询中,显而易见的是name。这可能足以使查询运行得足够快(除非您的所有产品都是汽车)。

除此之外,还值得列出可能访问数据的常见方式,例如

  1. 获取属于某个类别的产品列表 - category 上的索引可能会有所帮助
  2. 但是,获取当前可用产品的列表 - availability 上的索引可能无济于事,因为大部分 products 可能满足此条件。

除非您要处理大量数据,否则这通常是您需要做的全部事情,而且“以防万一”添加索引通常不是一个好主意,因为维护它们会产生开销。但是,如果您的系统确实存在性能问题,那么值得考虑如何在查询中使用列组合,阅读有关 postgres 查询优化器等的信息。

回答您的最后一个问题 - 可能,但这远不是要考虑的第一件事。

【讨论】:

  • "确保主键上有唯一索引" - Postgres 中的 PK 上不可能没有索引或非唯一索引
  • 你的“几条规则”不好。 1.废话,PK是在Postgres中自动使用唯一的btree索引实现的。 (要完全清楚,Postgres 将允许在同一列上创建另一个索引,无论是否唯一,但这将是毫无意义的、昂贵的浪费。2. 大部分是正确的。3. 没有根据。通常,多列索引已经足够好了,它是为 PK 自动创建的,并且在大多数情况下为 FK 创建是有意义的。如果您没有额外的要求,则不需要在部分键上添加额外的索引。
  • 这些是学习者的经验法则 - 你或我可能会做不同的事情。
  • @Sonic:其余的答案很有用,但你的主要“少数规则”大多是不正确和误导的。
  • 我明白你的意思 - 我已经对答案的前半部分进行了更改,包括一个新段落。
【解决方案2】:

那么您设置索引的方式是绝对正确的。索引与 order by 子句无关。

设计 SQL 查询时的一些要点

  1. 始终将条件放在 WHERE 子句中,这将过滤最大行,例如上面的查询 name ='car' 将过滤产品中的最大记录。

  2. 不要使用 ">=" 使用 ">" ,因为如果等于失败,大于或等于总是首先检查更大,这会降低查询性能。

  3. 按照 where 子句的排列顺序创建单个索引。

  4. 尝试使用 ANY 来最小化 IN 子句。

谢谢 阿南特

【讨论】:

  • 这是 postgresql 的具体建议还是一般建议?
  • 另外,“Indexes 与 order by 子句无关”这句话也不正确。索引可以帮助数据库对结果进行排序。
猜你喜欢
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-16
  • 1970-01-01
  • 2017-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多