【问题标题】:Indexing (x <> 4 OR y <> 5)索引(x <> 4 或 y <> 5)
【发布时间】:2020-09-29 11:27:34
【问题描述】:

我正在寻找一个索引来快速完成以下操作:

CREATE TABLE mytable (
    t1 INT NOT NULL, 
    t2 INT NOT NULL, 
    latest_creation_date INT NOT NULL, 
    data_category_id CHAR(36) NOT NULL, 
    value VARCHAR(255) NOT NULL,  
    PRIMARY KEY(latest_creation_date, t1, t2, data_category_id))

查询是删除,内容如下:

delete 
from mytable 
where 
    latest_creation_date = 0 
    and Not (
           (t1 = 5 and t2 = 10)
        or (t1 = 15 and t2 = 20)
        or (t1 = 215 and t2 = 320)
        or (t1 = 315 and t2 = 420)
        ...
        or (t1 = 415 and t2 = 520)
        or (t1 = 515 and t2 = 620));

所以它会删除所有与 t1 和 t2 上的几百个条件不匹配的行。

explain 进行顺序扫描并重新排列查询:

Delete on mytable  (cost=0.00..2517652.30 rows=38182950 width=6)
   ->  Seq Scan on mytable  (cost=0.00..2517652.30 rows=38182950 width=6)
         Filter: ((latest_creation_date = 0) AND ((t1 <> 5) OR (t2 <> 10)) AND ((t1 <> 15) OR (t2 <> 20)) AND ((t1 <> 215) OR (t2 <> 320)) AND ((t1 <> 315) OR (t2 <> 420)) AND ((t1 <> 415) OR (t2 <> 520)) AND ((t1 <> 515) OR (t2 <> 620)))

我可以创建一个可以避免全扫描的索引吗?

提前致谢!

【问题讨论】:

  • 这样的索引应该是可能的postgresql.org/docs/8.0/indexes-partial.html
  • 即使您在 t1 和 t2 上添加索引,查询优化器也可能会选择扫描以删除 大部分
  • 嗯,值正在改变,@AntonínLejsek,我希望使用主键。但我认为这是不可能的,因为 &lt;&gt; 比较。
  • 您可能可以通过设置enable_seqscan = off 让它使用现有索引,但这实际上可能不会更快。

标签: sql postgresql indexing


【解决方案1】:

虽然它应该是相同的计划,但其中任何一个都会导致改进计划吗?

delete from mytable 
where latest_creation_date = 0 and
      (t1, t2) not in ((5, 10), (15, 20), . . . );

或者:

delete from mytable 
where latest_creation_date = 0 and
      (t1, t2) not in (select v.*
                       from (values (5, 10), (15, 20), . . .) v(t1, t2)
                      );

【讨论】:

  • and 在您的第一个删除语句中丢失!
  • 难以置信! not in () 让 postgres 创建一个散列子计划,并将性能从 50 分钟提高到 14 秒!
【解决方案2】:

我采纳了@GordonLinoff 的建议,并提出了他的第二个版本。

这减少了我的实际时间从 55 分钟到 14 秒(表有 3700 万行)。这可能吗???

这里是对应的解释输出:


---------------------------------------------------------------------------------------------------------------------------
 Delete on mytable e  (cost=107.45..1562955.75 rows=19096080 width=6)
   ->  Seq Scan on data_category_evaluation e  (cost=107.45..1562955.75 rows=19096080 width=6)
         Filter: (((stress_test_run_id)::text = 'null'::text) AND (latest_creation_date = 0) AND (NOT (hashed SubPlan 1)))
         SubPlan 1
           ->  Values Scan on "*VALUES*"  (cost=0.00..99.78 rows=3070 width=8)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多