两列的唯一索引加上每一列的单独索引?
Posted
技术标签:
【中文标题】两列的唯一索引加上每一列的单独索引?【英文标题】:Unique index on two columns plus separate index on each one? 【发布时间】:2009-01-31 21:02:55 【问题描述】:我对数据库优化不太了解,但我正在努力理解这个案例。
假设我有下表:
cities
===========
state_id integer
name varchar(32)
slug varchar(32)
现在,假设我想执行这样的查询:
SELECT * FROM cities WHERE state_id = 123 AND slug = 'some_city'
SELECT * FROM cities WHERE state_id = 123
如果我希望一个城市的“slug”在其特定州内是唯一的,我会在 state_id 和 slug 上添加一个唯一索引。
这个索引够吗?或者我还应该在 state_id 上添加另一个以便优化第二个查询?还是第二个查询自动使用唯一索引?
我正在研究 PostgreSQL,但我觉得这个案例非常简单,以至于大多数 DBMS 的工作方式都差不多。
另外,我知道这肯定不会对小桌子产生影响,但我的示例很简单。想想 200k+ 行的表。
谢谢!
【问题讨论】:
看来这个主题比我最初想象的要复杂。谢谢大家的意见。 【参考方案1】:(state_id, slug) 上的单个唯一索引就足够了。可以肯定的是,当然,您需要运行 EXPLAIN 和/或 ANALYZE(可能在 http://explain.depesz.com/ 之类的帮助下),但最终哪些索引是合适的,很大程度上取决于您将运行的查询类型。请记住,索引使 SELECT 更快,而 INSERT、UPDATE 和 DELETE 更慢,因此理想情况下,您只需要实际需要的索引。
此外,PostgreSQL 有一个智能查询优化器:它将使用完全不同的搜索计划来处理小表和大表的查询。如果表很小,它只会进行顺序扫描,甚至不会打扰 any 索引,因为使用它们的开销比通过表的暴力筛选要高。一旦表大小超过阈值,这将更改为不同的计划,并且如果表再次变大,或者如果您更改 SELECT,或者......
总结:您不能相信 EXPLAIN 和 ANALYZE 对比您的实际数据小得多或不同的数据集的结果。让它发挥作用,然后再让它变得更快(如果你需要的话)。
【讨论】:
【参考方案2】:[编辑:误读了问题...希望我的回答现在更相关!]
在您的情况下,我建议在 (state_id, slug)
上设置 1 个索引。如果您只需要通过 slug
进行搜索,请仅在该列上添加索引。如果你有这些,那么在state_id
上添加另一个索引是不必要的,因为第一个索引已经涵盖了它。
只要在 WHERE 子句中使用 其列的初始段,就可以使用索引。所以例如列 A、B 和 C 上的索引将优化包含涉及 A、B 和 C 的 WHERE 子句、仅包含 A 和 B 的 WHERE 子句或仅包含 A 的 WHERE 子句的查询。请注意,列在索引定义中出现的顺序非常重要——这个示例索引不能用于只涉及 B 和/或 C 的 WHERE 子句。
(当然,是否实际使用特定索引取决于查询优化器,但在您有 200k 行的情况下,您可以保证通过 state_id
或 slug
或两者进行简单搜索将使用一个指数。)
【讨论】:
【参考方案3】:任何体面的优化器都会在三列上看到一个索引 - 比如说:
CREATE INDEX idx_1 ON SomeTable(Col1, Col2, Col3);
并将在以下任何情况下使用该索引:
WHERE Col1 = ...something...
WHERE Col1 = ...something... AND Col2 = ...otherthing...
WHERE Col3 = ....whatnot....
AND Col1 = ...something....
AND Col2 = ...otherthing...
也就是说,如果有条件应用于索引列的任何连续前导子集,它将使用索引。虽然我使用了相等,但它也可以应用于范围(例如,开 - 刚好大于)或闭(在两个值之间)。
【讨论】:
【参考方案4】:要进行优化,请使用 EXPLAIN http://www.postgresql.org/docs/7.4/static/sql-explain.html 并亲自查看。 但优化并不是制作这些索引的最重要原因;首先,它是一个限制数据库不合逻辑的约束。
【讨论】:
以上是关于两列的唯一索引加上每一列的单独索引?的主要内容,如果未能解决你的问题,请参考以下文章
使用同一 Dataframe 中另一列的 int 作为索引获取列中的列表值