如何衡量数据库索引的成本?

时间:2012-10-25 21:10:40

标签: sql database postgresql indexing

是否有一种很好的方法来判断在Postgres中创建数据库索引的成本(较慢INSERTS,构建索引的时间,重新索引的时间)是否值得获得性能提升(更快{{1} }})?

3 个答案:

答案 0 :(得分:5)

我实际上不同意Hexist。 PostgreSQL的规划器非常好,它支持基于物理顺序扫描对表文件的良好顺序访问,因此索引不一定有用。此外,在许多情况下,计划者必须选择一个索引。此外,您已经为唯一约束和主键创建主键。

我认为PostgreSQL的一个很好的默认位置(MySQL btw完全不同!)是等到你需要一个索引来添加一个,然后只添加你最需要的索引。然而,这只是一个起点,它假设缺乏查看查询计划的一般经验,或者缺乏对应用程序可能去向的理解。在这些方面有经验很重要。

通常,如果您的表可能跨越10页以上(即40kb的数据和标题),那么外键是个好主意。可以明确地假设这些。跨越1页的小型查找表应该从不具有非唯一索引,因为这些索引永远不会用于选择(没有查询计划胜过单页的顺序扫描)。

除此之外,您还需要查看数据分布。索引布尔列通常是一个坏主意,并且有更好的方法来索引与布尔搜索相关的事物(部分索引是一个很好的例子)。类似地,索引常用函数输出有时似乎是一个好主意,但情况并非总是如此。考虑:

CREATE INDEX gj_transdate_year_idx ON general_journal (extract('YEAR' FROM transdate));

这不会有太大作用。但是,如果通过递归CTE与稀疏索引扫描配对,则transdate索引可能会有用。

一旦基本索引到位,那么问题就变成了你需要添加的其他索引。这通常最好留待以后使用案例审查,而不是最初设计的。人们发现在PostgreSQL上使用较少的索引可以显着提高性能,这种情况并不少见。

要考虑的另一个主要问题是您创建了哪种索引,这些索引通常是特定于用例的。例如,如果常规对域很重要,并且如果您经常基于初始元素进行搜索,那么数组记录上的b树索引可能有意义,但如果常规不重要,我会建议使用GIN索引,因为btree会做得很少(当然这是一个原子红旗,但有时候在Pg中有意义)。即使常规很重要,有时你也需要GIN索引,因为你需要能够进行交换式扫描,就好像不是普通性一样。如果使用ip4r存储cidr块并使用EXCLUDE约束来确保没有任何块包含任何其他块(实际扫描需要使用重叠运算符而不是包含运算符,因为您不知道哪一侧是操作员将在上面找到违规行为。

这又是一些特定于数据库的。例如,在MySQL上,Hexist的建议是正确的。但是,在PostgreSQL上,关注问题是件好事。

就测量而言,最好的工具是EXPLAIN ANALYZE

答案 1 :(得分:3)

一般来说,除非你有一个日志或归档表,你不经常选择(或者如果他们需要一段时间才能运行),你应该索引你的select / update / deelete语句将使用的任何内容在where子句中。

然而,这并不像看起来那么简单,因为只是因为在where子句中使用了列并且索引,并不意味着sql引擎将能够使用索引。使用postgresql的EXPLAINEXPLAIN ANALYZE功能,您可以检查选择中使用了哪些索引,并帮助您确定列上的索引是否可以帮助您。

这通常是正确的,因为没有索引,您的选择速度会从某些O(log n)查找操作下降到O(n),而您的插入速度只会从cO(log n)提高到dO(log n)其中d通常小于c,即你可以通过没有索引加快插入速度,但如果它们没有编入索引你就会杀死你的选择速度,所以拥有一个索引几乎总是值得的如果您要选择反对它,请使用您的数据。

现在,如果你有一些小表,你进行了大量的插入和更新,并经常删除所有条目,并且只定期进行一些选择,那么没有任何索引可能会更快。然而,这将是一个相当特殊的情况,所以你必须做一些基准测试,并决定它是否在你的具体情况下有意义。

答案 2 :(得分:0)

好问题。我想补充一下@hexist已经提到过的内容以及@ ypercube链接提供的信息。

按照设计,数据库不知道表的哪个部分会找到满足提供的predicates的数据。因此,DB将对所有表的数据执行完整或顺序扫描,过滤所需的行。

索引是一种特殊的数据结构,对于给定的key,可以精确指定将在哪些行中找到这样的值。涉及索引时的主要区别:

  1. 索引扫描本身就有成本,即DB必须先在索引中找到一个值;
  2. 从表格中读取特定数据会产生额外费用。
  3. 使用索引将导致随机IO模式,与完整扫描中使用的顺序模式相比。您可以谷歌搜索随机和顺序磁盘访问的比较数字,但它可能会有一个数量级的差异(当然随机速度较慢)。

    但是,很明显,在某些情况下,索引访问将更便宜,而在其他情况下,应首选全扫描。这取决于指定谓词将返回多少行(总共),或者它的选择性:

    1. 如果谓词将返回相对较少的行数,比如少于总数的10%,那么直接通过Index选择那些行似乎很有价值。这是主要/唯一键或查询的典型案例,例如:I need address information for customer with internal number = XXX;
    2. 如果谓词对选择性没有太大影响,即如果返回30%(或更多)行,那么执行全扫描会更便宜,'顺序磁盘访问将随机打乱,数据将更快地传送。涵盖大区域(如一个月或所有客户)的所有报告均落在此处;
    3. 如果需要获取有序的值列表并且有索引,那么执行索引扫描是最快的选择。当需要按某些列排序的报告数据时,这是#2的特例;
    4. 如果列中的不同值的数量与值的总数相比相对较小,那么Index将是一个不错的选择。这是一个名为Loose Index Scan的案例,典型的查询类似于:I need 20 most recent purchases for each of the top 5 categories by number of goods
    5. DB如何决定做什么,索引还是全扫描?这是运行时决策,它基于统计信息,因此请务必保持最新状态。实际上,上面提供的数字没有实际值,您必须独立评估每个查询。

      所有这些都是对所发生情况的粗略描述。我非常建议调查How PostgreSQL Planner Uses Statistics,这是我在这个问题上看到的最好的。

相关问题