这个PostgreSQL查询应该使用索引吗?

时间:2012-12-13 08:07:36

标签: postgresql indexing

我有两张桌子:

CREATE TABLE soils (
    sample_id       TEXT PRIMARY KEY, 
    project_id      TEXT, 
    technician_id   TEXT
);
CREATE INDEX soils_idx
ON soils
USING btree
(sample_id COLLATE pg_catalog."default");

CREATE TABLE assays (
    sample_id   TEXT PRIMARY KEY, 
    mo_ppm      NUMERIC
    );
CREATE INDEX assays_idx
ON assays
USING btree
(sample_id COLLATE pg_catalog."default");

每个表包含大约50万条记录,实际上,每个类型大约有20个,TEXT类型(在上面发布的DDL中省略,以节省时间)。

执行查询时:

EXPLAIN SELECT
   s.sample_id, s.project_id, s.technician_id, a.mo_ppm
FROM
   soils AS s INNER JOIN assays AS a ON s.sample_id = a.sample_id

我得到2个SEQ SCAN,而不是查找索引。这是预期的行为吗?

2 个答案:

答案 0 :(得分:4)

由于您没有WHERE条件,因此您可以有效地阅读整个表格。运行顺序扫描并且根本不涉及任何索引会更便宜。

尝试:

EXPLAIN
SELECT s.sample_id, s.project_id, s.technician_id, a.mo_ppm
FROM   soils s
JOIN   assays a USING (sample_id)
WHERE  <some condition that returns few rows>;

...应该使用与WHERE条件匹配的索引。

您无需在PRIMARY KEY列上定义索引。 PK约束自动使用唯一索引实现。您的附加索引是多余的,没有用处。

外键列上的索引是个好主意,但是在您的示例中没有一个看起来很奇怪。就像这两个表可以组合成一个。可能只是对测试用例的过度简化。

最后,对于大表,我会考虑使用简单的integer主键而不是text,可能是serial列。这通常更快。

答案 1 :(得分:1)

是的,这是预期的行为。另一方面,它取决于您的random_page_costseq_page_costeffective_cache_size设置。您的查询没有WHERE子句,因此按顺序读取所有内容可能会更快。您可以尝试惩罚顺序扫描:

set enable_seqscan = off;
explain analyse <your query>;

然后比较计划/成本/ IO等待(不可能禁用seq-scan但成本非常高 - ~1e7(或1e8))。

如果查询中有SSD和WHERE子句,则可以降低random_page_cost to 1.5..2.5并鼓励PG使用索引。