丢弃索引会重置性能增益吗?

时间:2014-08-14 17:58:09

标签: sql postgresql indexing

我尝试在包含数千万行的表中的外键列上添加索引,并且我运行的半复杂查询从4秒到10毫秒执行时间。太好了!

然后我再次尝试删除它以进行更多测试,但是当我执行相同的查询时,它仍然需要10毫秒(与添加索引之前的4秒相比)。

删除索引会重置性能提升吗?如果没有,我怎样才能完全删除索引?

查询看起来像这样(此查询每分钟运行一次并将结果存储在另一个表中):

SELECT COUNT(*) AS count
FROM (
   SELECT MAX(ze.timestamp) AS time, r.device_id
   FROM loc_zone_events ze
   INNER JOIN loc_zones z ON ze.zone_id = z.id
   INNER JOIN raw_events r ON ze.raw_event_id = r.id
   WHERE z.app_id = 1
   AND ROUND(EXTRACT('epoch' FROM NOW() - ze.timestamp) / 60) BETWEEN 0 AND 10
   GROUP BY r.device_id
   ORDER BY time DESC
   ) AS t

2 个答案:

答案 0 :(得分:4)

DROP INDEX 完全删除索引。

事务必须在新查询生效之前提交,但这通常不是问题。您可能正在看到其他测试工件,如:

  • Postgres在统计略有变化后翻转到其他查询计划。这表明您的cost settings might be inappropriate or some other poor configuration.
  • 重复执行查询已填充缓存(可以为大表创建 big 差异)。对于中途可比较的结果,所有候选人都会进行几次。
  • 您的查询基于“过去十分钟”。可以有1000行,10分钟后,可以只有1.可以产生差异。

查询

首先,删除完全不必要的部分:

SELECT COUNT(*) AS count
FROM (
   SELECT 1
   FROM   loc_zones       z
   JOIN   loc_zone_events ze ON ze.zone_id = z.id
   JOIN   raw_events      r  ON r.id = ze.raw_event_id
   WHERE  z.app_id = 1
   AND    round(EXTRACT('epoch' FROM NOW() - ze.timestamp) / 60) BETWEEN 0 AND 10
   GROUP  BY r.device_id
   ) AS t;

或者:

SELECT COUNT(DISTINCT r.device_id) AS count
FROM   loc_zones       z
JOIN   loc_zone_events ze ON ze.zone_id = z.id
JOIN   raw_events      r  ON r.id = ze.raw_event_id
WHERE  z.app_id = 1
AND    round(EXTRACT('epoch' FROM NOW() - ze.timestamp) / 60) BETWEEN 0 AND 10

(不一定更快,count(DISTINCT col)不是表演英雄。)

但还有更多:

WHERE条件round(...)不是sargable。要检索“最近10分钟”的事件,请改为使用:

...
AND    ze.timestamp >= now() - interval '10 min'
AND    ze.timestamp <  now();  -- only if there can be timestamps in the future 

这是可以使用的,可以使用ze.timestamp上的索引。

注意: 您的表达式使用round()代替trunc(),这有效 覆盖范围(-0.5, 10.5),如果没有未来的时间戳,则为11分钟(不是10分钟)或 10.5分钟。以某种方式处理这种差异......

索引

由于只有最后10分钟似乎相关,您可以使用部分索引进一步改进。这里的特殊困难是移动时间范围。这个相关的答案有一个完整的解决方案:

在此基础上,您将获得一个部分索引,如:

CREATE INDEX ze_timestamp_recent_idx ON tbl (timestamp DESC);
WHERE  created_at > f_min_ts();

并调整查询,如:

WHERE  ...
AND    ze.timestamp > f_min_ts()   -- to match partial index
AND    ze.timestamp >= now() - interval '10 min'
AND    ze.timestamp <  now();

除此之外:不要使用基本类型名称timestamp作为列名。

答案 1 :(得分:0)

这取决于您使用的数据库。

1。)如果您有一个大型数据库(如您所述)..很可能您会对其进行分区。并在分区上创建索引。

2。)如果您在运行查询时在大型表上创建索引,该查询也会减慢它的速度。 b / c现在你的两个进程正在使用数据库资源。

3。)当你运行查询时,是否还有其他进程插入/更新/删除行?你有足够的临时空间吗?你的查询是在进行排序/分组操作吗?

这些都很重要,而且更重要的是数据库的架构......在我看来。

喝彩!