【问题标题】:How avoid the scan in the main table如何避免主表中的扫描
【发布时间】:2017-07-06 16:23:11
【问题描述】:

我有一个表在多个表中使用继承进行了几天的分区。

有一个插入触发器可以将数据插入到正确的表中,所以理论上avl表不应该有任何数据

CREATE OR REPLACE FUNCTION avl_db.avl_insert_trigger()
  RETURNS trigger AS
$BODY$
BEGIN
    IF ( NEW.event_time >= '2017-06-01 00:00:00' AND NEW.event_time < '2017-06-02 00:00:00' ) THEN 
        INSERT INTO avl_db.avl_20170601 VALUES (NEW.*);
    ELSEIF ( NEW.event_time >= '2017-06-02 00:00:00' AND NEW.event_time < '2017-06-03 00:00:00' ) THEN 
        INSERT INTO avl_db.avl_20170602 VALUES (NEW.*);
    ELSEIF ( NEW.event_time >= '2017-06-03 00:00:00' AND NEW.event_time < '2017-06-04 00:00:00' ) THEN 
        INSERT INTO avl_db.avl_20170603 VALUES (NEW.*);
    ELSEIF ( NEW.event_time >= '2017-06-04 00:00:00' AND NEW.event_time < '2017-06-05 00:00:00' ) THEN 
        INSERT INTO avl_db.avl_20170604 VALUES (NEW.*);
    ELSEIF ( NEW.event_time >= '2017-06-05 00:00:00' AND NEW.event_time < '2017-06-06 00:00:00' ) THEN 
        INSERT INTO avl_db.avl_20170605 VALUES (NEW.*);
....
    ELSE
        RAISE EXCEPTION 'Date out of range.';
    END IF;

    RETURN NULL;

每个表都有一个检查约束和索引,所以只检查日期正确的表

CONSTRAINT avl_20170605_event_time_check 
CHECK (event_time >= '2017-06-05 00:00:00'::timestamp without time zone 
   AND event_time <  '2017-06-06 00:00:00'::timestamp without time zone)

CREATE INDEX avl_20170605__event_time_idx
  ON avl_db.avl_20170605
  USING btree
  (event_time);

问题是当使用event_time 进行筛选时,仍然对主avl 表进行一些操作。

explain analyze
    SELECT *
    FROM avl_db.avl
    WHERE event_time between '2017-06-05 09:40:44'::timestamp without time zone - '6 minute'::interval
                         AND '2017-06-05 09:40:44'::timestamp without time zone - '1 minute'::interval

您可以看到使用来自avl_20170605__event_time_idx 的索引并忽略其余表,但也可以尝试对avl 进行 Seq Scan。

Append  (cost=0.00..720.98 rows=7724 width=16) (actual time=0.044..5.523 rows=7851 loops=1)
  ->  Seq Scan on avl  (cost=0.00..0.00 rows=1 width=16) (actual time=0.001..0.001 rows=0 loops=1)
        Filter: ((event_time >= '2017-06-05 09:34:44'::timestamp without time zone) AND (event_time <= '2017-06-05 09:39:44'::timestamp without time zone))
  ->  Index Scan using avl_20170605__event_time_idx on avl_20170605  (cost=0.42..720.98 rows=7723 width=16) (actual time=0.042..5.110 rows=7851 loops=1)
        Index Cond: ((event_time >= '2017-06-05 09:34:44'::timestamp without time zone) AND (event_time <= '2017-06-05 09:39:44'::timestamp without time zone))
Planning time: 3.050 ms
Execution time: 5.737 ms

我想知道优化器是否有办法停止尝试扫描并附加表avl

【问题讨论】:

  • 对于单行,执行Seq Scan 是唯一有效的方法。
  • 另外,请向我们展示您的创建触发器——它是在之前还是之后?
  • @a_horse_with_no_name 我看到了row=1。但这没有任何意义,那里不应该有任何行。有没有办法我可以看到那里有哪一行?我的问题更像是当我添加 CHECK 约束时,优化器只检查一个表。所以也许我可以设置所以忽​​略主表。
  • row=1 是一个估计。该表的实际行数确实是0(参见(actual ... rows=0 部分)。有了行估计和实际行数,Seq Scan 优化器可以采取的最佳选择。执行计划不是静态的。如果行数和值的分布发生变化,优化器将选择一个不同的(更好的)计划来处理更多的行。目前一切正常,您无需担心。
  • @a_horse_with_no_name 好的,顺便说一句,谢谢你的解释,现在我明白了如何阅读计划。附加行与索引扫描中的相同。

标签: sql postgresql partitioning sql-execution-plan postgresql-9.4


【解决方案1】:

这是正常的,应该如此。

对分区表的每次扫描也会扫描(通常是空的)父表,因为它没有(也不能)像子表那样具有CHECK 约束。

您可以看到,此扫描不会对整个查询持续时间产生任何影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-04
    • 2021-11-04
    • 1970-01-01
    • 1970-01-01
    • 2019-07-17
    • 2014-02-07
    相关资源
    最近更新 更多