【问题标题】:Slow PostgreSQL query not using index不使用索引的慢 PostgreSQL 查询
【发布时间】:2014-04-28 01:19:09
【问题描述】:

我有一个简单的 Django 站点,使用 PostgreSQL 9.3 数据库,有一个存储用户帐户(例如姓名、电子邮件、地址、电话、活动等)的表。但是,我的用户模型相当大,大约有 260 万条记录。我注意到 Django 的管理有点慢,所以使用 django-debug-toolbar,我注意到几乎所有查询都在 1 毫秒内运行,除了:

SELECT COUNT(*) FROM "myapp_myuser" WHERE "myapp_myuser"."active" = true;

大约需要 7000 毫秒。但是,active 列是使用 Django 的标准 db_index=True 进行索引的,它会生成索引:

CREATE INDEX myapp_myuser_active
  ON myapp_myuser
  USING btree
  (active);

通过EXPLAIN 查看查询:

EXPLAIN ANALYZE VERBOSE
SELECT COUNT(*) FROM "myapp_myuser" WHERE "myapp_myuser"."active" = true;

返回:

Aggregate  (cost=109305.45..109305.46 rows=1 width=0) (actual time=7342.973..7342.974 rows=1 loops=1)
  Output: count(*)
  ->  Seq Scan on public.myapp_myuser  (cost=0.00..102638.16 rows=2666916 width=0) (actual time=0.035..4765.059 rows=2666337 loops=1)
        Output: id, created, category_id, name, email, address_1, address_2, city, active,  (...)
        Filter: myapp_myuser.active
Total runtime: 7343.031 ms

它似乎根本没有使用索引。我读对了吗?

仅运行 SELECT COUNT(*) FROM "myapp_myuser" 在大约 500 毫秒内完成。即使唯一使用的列已编入索引,为什么运行时间会出现如此差异?

如何更好地优化此查询?

【问题讨论】:

  • 它没有使用索引。是否有 任何 行“活动”为假?
  • 重现性如何?我猜想没有 where 子句的查询会更快,只是因为您在使用 where 子句的查询之后立即运行它,已经将所有数据拉入内存。

标签: django postgresql


【解决方案1】:

您从宽表中选择了很多列。所以这可能无济于事,即使它确实会导致位图索引扫描。

试试partial index

create index on myapp_myuser (active) where active = true;

我制作了一个包含几百万行的测试表。

explain analyze verbose 
select count(*) from test where active = true;

"Aggregate  (cost=41800.79..41800.81 rows=1 width=0) (actual time=500.756..500.756 rows=1 loops=1)"
"  Output: count(*)"
"  ->  Bitmap Heap Scan on public.test  (cost=8085.76..39307.79 rows=997200 width=0) (actual time=126.233..386.834 rows=1000000 loops=1)"
"        Output: id, active"
"        Filter: test.active"
"        ->  Bitmap Index Scan on test_active_idx1  (cost=0.00..7836.45 rows=497204 width=0) (actual time=123.398..123.398 rows=1000000 loops=1)"
"              Index Cond: (test.active = true)"
"Total runtime: 500.794 ms"

当您编写希望使用部分索引的查询时,您需要匹配表达式和 WHERE 子句。在 PostgreSQL 中使用 WHERE active is true 是有效的,但它与部分索引中的 WHERE 子句不匹配。这意味着您将再次获得顺序扫描。

【讨论】:

  • 谢谢。我没有得到 500ms,但我确实得到了 2000ms,比 7000ms 好一点。
猜你喜欢
  • 2021-09-19
  • 2012-05-21
  • 1970-01-01
  • 2015-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多