postgresql – postgres 9.6索引只扫描功能索引逻辑上可能但不执行

我在Postgres发布的docs / wiki中阅读了功能索引和仅索引扫描.

我现在有一个查询:

SELECT(xpath('/document/uuid/text()',xmldata))[1]::text,(xpath('/document/title/text()',xmldata))[1]::text
FROM xmltable
WHERE(xpath('/document/uuid/text()',xmldata))[1]::text = 'some-uuid-xxxx-xxxx'

和索引:

CREATE INDEX idx_covering_index on xmltable using btree (
    ((xpath('/document/uuid/text()',xmldata))[1]::text),((xpath('/document/title/text()',xmldata))[1]::text)
)

这个索引是逻辑地查看覆盖索引,并应该启用仅索引扫描,因为所有查询的值都包含在索引(uuid和title)中

我现在知道,如果函数调用中使用的列也包含在内,那么Postgres只会识别函数索引的覆盖索引

例如.:

SELECT to_upper(column1) from table where id >10

1)不能被这个索引所涵盖:

CREATE INDEX idx_covering_index on xmltable using btree (id,to_upper(column1));

2)但可以被这个覆盖:

CREATE INDEX idx_covering_index on xmltable using btree (column1,id,to_upper(column1));

从而导致仅索引扫描.

如果我现在尝试使用我的xml设置:

CREATE INDEX idx_covering_index on xmltable using btree (xmldata,((xpath('/document/uuid/text()',xmldata))[1]::text)
)

我收到一个错误:

data type xml has no default operator class for access method “btree”

不幸的是,通常使用的“text_ops”或“text_pattern_ops”不接受“xml”作为输入 – 从而渲染我的索引 – 虽然它将覆盖所有值 – 无法支持仅索引扫描.

这可以以提供仅索引扫描的可能性来处理吗?

@ EDIT1:

我知道postgres不能使用1)中的索引作为覆盖索引,但可以使用索引,如2)

我也尝试用非常简单的表来验证这个行为,我也记得要读这个 – 但是我不能忘记我的生活.

create table test (
    id serial primary key,quote text
)



insert into test (number,quote) values ('I do not know any clever quotes');
insert into test (number,quote) values ('I am sorry');



CREATE INDEX idx_test_functional on test using btree ((regexp_replace(quote,'^I ','BillDoor ')));
set enable_seqscan = off;

analyze test;

explain select quote from test where regexp_replace(quote,'BillDoor ') = 'BillDoor do not know any clever quotes'

--> "Index Scan using idx_test_functional on test  (cost=0.13..8.15 rows=1 width=27)"

drop index idx_test_functional;
CREATE INDEX idx_test_functional on test using btree (quote,(regexp_replace(quote,'BillDoor ')));

analyze test;

explain select quote from test where regexp_replace(quote,'BillDoor ') = 'BillDoor do not know any clever quotes'

--> "Index Only Scan using idx_test_functional on test  (cost=0.13..12.17 rows=1 width=27)"

@ EDIT2:

xmltable的全表定义:

id serial primary key (clustered),xmldata xml (only data used to filter queries)
history xml (never queried or read,just kept in case of legal inquiry)
fileinfo text (seldom quieried,sometimes retrieved)
"timestamp" timestamp (mainly for legal inquiries too)

该表包含大约:500.000条记录,xmldata的大小在350到800字节之间,历史要大得多,但很少被检索,从未在过滤器中使用

为了记录,确保得到真正的结果,我总是在创建或删除索引后分析xmltable

查询的完整执行计划:

explain analyze select (xpath('/document/uuid/text()',d.xmldata))[1]::text as uuid
from xmltable as d
where
(xpath('/document/uuid/text()',d.xmldata))[1]::text = 'some-uuid-xxxx-xxxx' and (xpath('/document/genre/text()',d.xmldata))[1]::text = 'bio'

被这些印度所覆盖:

create index idx_genre on xmltable using btree (((xpath('/document/genre/text()',xmldata))[1]::text));

create index idx_uuid on xmltable using btree (((xpath('/document/uuid/text()',xmldata))[1]::text)); 

create index idx_uuid_genre on xmltable using btree (((xpath('/document/uuid/text()',((xpath('/document/genre/text()',xmldata))[1]::text));

首先导致:

"Index Scan using idx_genre on xmldata d  (cost=0.42..6303.05 rows=18154 width=32)"
"  Index Cond: (((xpath('/document/genre/text()'::text,xmldata,'{}'::text[]))[1])::text = 'bio'::text)"
"  Filter: (((xpath('/document/uuid/text()'::text,'{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text)"

公平的我以为,只是为了测试我会强迫它使用 – 在我的脑海 – 覆盖索引:

drop index idx_uuid;
drop index idx_genre;

现在我得到:

"Bitmap Heap Scan on xmltable d  (cost=551.13..16025.51 rows=18216 width=32)"
"  Recheck Cond: ((((xpath('/document/genre/text()'::text,'{}'::text[]))[1])::text = 'bio'::text) AND (((xpath('/document/uuid/text()'::text,'{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text))"
"  ->  Bitmap Index Scan on idx_uuid_genre  (cost=0.00..546.58 rows=18216 width=0)"
"        Index Cond: ((((xpath('/document/genre/text()'::text,'{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text))"

我也尝试在索引中切换uuid和类型的位置,同样的执行计划.

编辑最后:为什么不可能

根据文档:postgresql可以在索引类型支持时进行索引扫描(即,btree始终支持这一点,GiST和SpGiST仅适用于某些特定的操作符,而GIN根本不起作用).并且可以从索引重建原始的索引值.

第二个要求是最有趣的.

在列的情况下,它是简单的(a,b),您的索引能够重建原始的存储值.

并且在功能索引工作的功能的情况下,您应该创建具有原始值的索引.这意味着(f1(a),f2(b))索引将再次出现,因为您无法从这些值重建索引数据(a,b).开发人员提出的解决方法是创建索引(f1(a),f2(b),a,b)在这种情况下,查询计划者能够确定可以运行仅索引扫描,因为索引包含原始数据.

并回到你的问题,创建索引只扫描xml列是不可能的:没有运算符支持xml数据比较关键的btree. xml数据的比较运算符没有定义.因此您不能在任何类型的索引中使用此列,但是您需要在仅索引扫描中提示查询优化器才能执行仅索引扫描.

编辑:(解决方案如何在特定的xpath表达式上实现仅索引扫描)

如果您知道这些数据将被频繁使用,我建议您通过触发功能解决此问题,并创建2个以上的字段并通过索引来覆盖.这样的事情

ALTER TABLE public.xmltable ADD COLUMN xpath_uuid character varying(36);
ALTER TABLE public.xmltable ADD COLUMN xpath_title character varying(100);


CREATE INDEX idx_covering_materialized_xml_data
  ON public.xmltable
  USING btree
  (xpath_uuid COLLATE pg_catalog."default",xpath_title COLLATE pg_catalog."default");

CREATE OR REPLACE FUNCTION public.introduce_xml_materialization()
  RETURNS trigger AS
$BODY$BEGIN 

NEW.xpath_uuid = (xpath('/document/uuid/text()',NEW.xmldata))[1]::text;
NEW.xpath_title = (xpath('/document/title/text()',NEW.xmldata))[1]::text;

RETURN NEW; 
END;$BODY$
  LANGUAGE plpgsql STABLE
  COST 100;



CREATE TRIGGER index_xml_data
  BEFORE INSERT OR UPDATE
  ON public.xmltable
  FOR EACH ROW
  EXECUTE PROCEDURE public.introduce_xml_materialization();

然后你可以简单地做:

SELECT  xpath_uuid,xpath_title
  FROM public.xmltable
  where xpath_uuid = ' uuid1 '

这将显示您仅索引扫描:

"Index Only Scan using idx_covering_materialized_xml_data on xmltable  (cost=0.14..8.16 rows=1 width=308)"
"  Index Cond: (xpath_uuid = ' uuid1 '::text)"

假设数据读取多于写入,这种方法将是最佳的.从插入或更新的成本,它通常与在xpath表达式上创建功能索引相同.

ORIGINAL RESPONSE:(对于愿意调整查询优化器的用户来说,可能很有意思)

那么问题是你的查询优化器认为xPath函数调用是最简单的.即它就像调用简单的数学运算符并且其成本是1.在这种情况下,查询优化器认为,从表中获取并再次计算更容易,然后进行纯索引扫描.

如果增加xpath调用成本,让我们说1000查询优化器会看到这样的调用显着更难(实际上是真的),并且将尝试执行仅索引扫描.在我的测试设置中,我已经执行了

update pg_proc set procost=1 where proname='xpath';

执行计划是

"Bitmap Heap Scan on xmltable  (cost=4.17..11.30 rows=3 width=64)"
"  Recheck Cond: (((xpath('/document/uuid/text()'::text,'{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text)"
"  ->  Bitmap Index Scan on idx_covering_index_3  (cost=0.00..4.17 rows=3 width=0)"
"        Index Cond: (((xpath('/document/uuid/text()'::text,'{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text)"

但是当我做的时候

update pg_proc set procost=1000 where proname='xpath';

执行计划正在切换到仅索引扫描

"Index Scan using idx_covering_index_3 on xmltable  (cost=0.15..31.20 rows=3 width=64)"
"  Index Cond: (((xpath('/document/uuid/text()'::text,'{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text)"

在我的卷(即没有数据)上,仅索引查询的最小成本显着小于原始索引表扫描中的最大成本,最大成本更大.因此,为了在查询优化上作弊,可能需要在xpath调用成本上放置更高的值.

希望这将有所帮助,出于好奇,只是向我们展示了使用仅索引查询的好处.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读601次。Oracle的数据导入导出是一项基本的技能,但是对于懂数据库却不熟悉Oracle的同学可能会有一定的障碍。正好在最近的一个项目中碰到了这样一个任务,于是研究了一下Oracle的数据导入导出,在这里跟大家分享一下。......_oracle 迁移方法 对比
文章浏览阅读553次。开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共700多人左右 1 + 2)。最近我们在使用MYSQL 8 的情况下(8.025)在数据库运行中出现一个问题 参数prefer_order_i..._mysql prefer_ordering_index
文章浏览阅读3.5k次,点赞3次,收藏7次。折腾了两个小时多才成功连上,在这分享一下我的经验,也仅仅是经验分享,有不足的地方欢迎大家在评论区补充交流。_navicat连接opengauss
文章浏览阅读2.7k次。JSON 代表 JavaScript Object Notation。它是一种开放标准格式,将数据组织成中详述的键/值对和数组。_postgresql json
文章浏览阅读2.9k次,点赞2次,收藏6次。navicat 连接postgresql 注:navicat老版本可能报错。1.在springboot中引入我们需要的依赖以及相应版本。用代码生成器生成代码后,即可进行增删改查(略)安装好postgresql 略。更改配置信息(注释中有)_mybatisplus postgresql
文章浏览阅读1.4k次。postgre进阶sql,包含分组排序、JSON解析、修改、删除、更新、强制踢出数据库所有使用用户、连表更新与删除、获取今年第一天、获取近12个月的年月、锁表处理、系统表使用(查询所有表和字段及注释、查询表占用空间)、指定数据库查找模式search_path、postgre备份及还原_pgsql分组取每组第一条
文章浏览阅读3.3k次。上一篇我们学习了日志清理,日志清理虽然解决了日志膨胀的问题,但就无法再恢复检查点之前的一致性状态。因此,我们还需要日志归档,pg的日志归档原理和Oracle类似,不过归档命令需要自己配置。以下代码在postmaster.c除了开启归档外,还需要保证wal_level不能是MINIMAL状态(因为该状态下有些操作不会记录日志)。在db启动时,会同时检查archive_mode和wal_level。以下代码也在postmaster.c(PostmasterMain函数)。......_postgresql archive_mode
文章浏览阅读3k次。系统:ubuntu22.04.3目的:利用向日葵实现windows远程控制ubuntu。_csdn局域网桌面控制ubuntu
文章浏览阅读1.6k次。表分区是解决一些因单表过大引用的性能问题的方式,比如某张表过大就会造成查询变慢,可能分区是一种解决方案。一般建议当单表大小超过内存就可以考虑表分区了。1,继承式分区,分为触发器(trigger)和规则(rule)两种方式触发器的方式1)创建表CREATE TABLE "public"."track_info_trigger_partition" ( "id" serial, "object_type" int2 NOT NULL DEFAULT 0, "object_name..._pg数据表分区的实现
文章浏览阅读3.3k次。物联网平台开源的有几个,就我晓得的有、、thingskit、JetLink、DG-iot(还有其他开源的,欢迎在评论区留言哦!),然后重点分析了下ThingsBoard、ThingsPanel和JetLink,ThingsBoard和Jetlinks是工程师思维产品,可以更多的通过配置去实现开发的目的,ThingsPanel是业务人员思路产品,或者开发或者用,避免了复杂的配置带来的较高学习门槛。ThingsBoard和Jetlinks是Java技术体系的,ThingsPanel是PHP开发的。_jetlinks和thingsboard
文章浏览阅读3.8k次。PostgreSQL 数据类型转换_pgsql数字转字符串
文章浏览阅读7k次,点赞3次,收藏14次。在做数据统计页面时,总会遇到统计某段时间内,每天、每月、每年的数据视图(柱状图、折线图等)。这些统计数据一眼看过去也简单呀,不就是按照时间周期(天、月、年)对统计数据进行分个组就完了嘛?但是会有一个问题,简单的写个sql对周期分组,获取到的统计数据是缺失的,即没有数据的那天,整条记录也都没有了。如下图需求:以当前月份(2023年2月)为起点,往后倒推一年,查询之前一年里每个月的统计数据。可见图中的数据其实是缺少的,这条sql只查询到了有数据的月份(23年的1月、2月,22年的12月)_如何用一条sql查出按年按月按天的汇总
文章浏览阅读3.8k次,点赞66次,收藏51次。PostgreSQL全球开发小组与2022年10月13日,宣布发布PostgreSQL15,这是世界上最先进的开源数据库的最新版本_mysql8 postgresql15
文章浏览阅读1.3k次。上文介绍了磁盘管理器中VFD的实现原理,本篇将从上层角度讲解磁盘管理器的工作细节。_smgrrelationdata
文章浏览阅读1.1k次。PostgreSQL设置中文语言界面和局域网访问_postgressql汉化
文章浏览阅读4.2k次。PostgreSQL 修改数据存储路径_如何设置postgresql 数据目录
文章浏览阅读4.7k次。在项目中用到了多数据源,在连接postgres数据库时,项目启动报错,说数据库连接错误,说dual不存在,网上好多教程都是说数据库查询的时候的大小写问题,而这个仅仅是连接,咋鞥却处理方法是修改application-dev.yml中的配置文件.项目中的druid参数是这样的:确实在配置文件中有个查询语句。_relation "dual" does not exist
文章浏览阅读4.9k次。PostgreSQL是一款强大的关系型数据库,但在实际使用过程中,许多用户经常会遇到慢SQL的问题。这些问题不仅会降低数据库性能,还会直接影响业务流程和用户体验。因此,本文将会深入分析PostgreSQL慢SQL的原因和优化方案,帮助用户更好地利用这个优秀的数据库系统。无论你是初学者还是专业开发者,本文都将为你提供实用的技巧和方法,让你的PostgreSQL数据库始终保持高效快速。_postgresql数据库优化
文章浏览阅读1.6k次。Linux配置postgresql开机自启_linux 启动pgsql
文章浏览阅读2k次。本篇介绍如何在centos7系统搭建一个postgresql主备集群实现最近的HA(高可用)架构。后续更高级的HA模式都是基于这个最基本的主备搭建。_postgresql主备