【PGCCC】 复合索引和部分索引,竟然能让查询速度提升 275 倍!

索引对于加速数据库查询和提高 PostgreSQL 应用程序的性能至关重要。但是,并非所有索引都以相同的方式发挥作用。复合索引和部分索引是两种常见类型,每种类型都有不同的用途和对性能的影响。本文我们将深入探讨复合索引和部分索引是什么、它们如何运作以及何时使用它们来为数据库实现最佳结果。
在这里插入图片描述

复合索引

复合索引是在多个列上创建的,使 PostgreSQL 能够高效处理搜索条件中包含多个列的查询。当查询频繁使用多个字段过滤或排序数据时,这种类型的索引尤其有用。例如,在“last_name”和“first_name”上同时创建索引可以加速查询中同时指定两个名称的搜索。

使用复合索引的优点

  • 复合索引可以充当覆盖索引,这意味着它们包含查询所需的所有列。这允许数据库直接从索引中检索数据,而无需查看主表,从而减少所需的 I/O
    操作数。
  • 如果我们经常运行按“last_name”和“first_name”排序的查询,则这些列上的复合索引将通过提供预先排序的顺序来加快它们的速度,从而使排序更快、更高效。
  • 我们还可以对相同的列使用具有 UNIQUE 约束的复合索引,以确保更快的性能和数据完整性。

使用复合索引的缺点

  • 如果复合索引包含查询中很少一起使用的列,则它不会提高性能,甚至可能由于更新索引所需的额外工作而降低性能。
  • 如果复合索引中的任何列频繁更新,则必须经常修改索引,这可能会对性能产生负面影响。
  • 通过 INSERT 或 UPDATE 查询频繁更新索引会增加存储使用量并需要更多维护。
  • 复合索引中列的顺序至关重要;只有当查询从第一列开始或按顺序匹配前几列时,PostgreSQL 才能有效地使用索引。
  • 当您的表具有许多唯一值时,请使用复合索引;如果只有少数唯一值,则复合索引可能无效。

复合索引示例

让我们考虑一个用于存储销售数据的简单表,该表具有主键,但没有其他索引。该表可能如下所示

postgres=# \d sales表“public.sales”列|类型|排序规则|可空|默认                 
-------------+-----------+-----------+-------------+---------------------------------------- 
sale_id |整数||非空|nextval('sales_sale_id_seq'::regclass) 
customer_id |整数||非空|  
product_id |整数||非空|  
sale_date |日期||非空| 
金额|数字(10,2)||非空| 
索引:“sales_pkey”主键,btree(sale_id)

让我们执行一个简单的SELECT查询来获取product_id = 408的所有销售信息,其中sale_date是2024-08-17

postgres = # EXPLAIN ANALYZE SELECT * FROM sales WHERE product_id = 408 AND sale_date = '2024-08-17';查询计划                                                     
------------------------------------------------------------------------------------------------------------------
收集(成本=1000.00..7310.30=3 宽度=22)(实际时间=4.374..19.059=4 循环=1)计划的工人:2启动的工人:2 -> 销售并行序列扫描(成本=0.00..6310.00=1 宽度=22)(实际时间=9.093..14.098=1 循环=3)过滤器:((product_id = 408AND(sale_date = '2024-08-17'::date))过滤器删除的行:166665
计划时间:0.251 毫秒
执行时间:19.078 毫秒
(8 行)

PostgreSQL 规划器选择使用并行顺序扫描来获取所需结果,这是有道理的,因为目前还没有索引。这需要19.078 毫秒才能完成。

现在,让我们在同一个表中的product_id和sale_date列上创建一个复合索引。

创建索引 idx_sales_product_id_sale_date ON sales(product_id, sale_date);
创建索引

现在,让我们再次运行相同的SELECT查询

解释分析选择*从销售中获取产品id = 408 和销售日期 = '2024-08-17';查询计划                                                               
--------------------------------------------------------------------------------------------------------------------------------------------------
销售位图堆扫描(成本=4.45..16.22=3 宽度=22)(实际时间=0.048..0.055=4 循环=1)重新检查条件:((product_id = 408AND(sale_date = '2024-08-17'::date))堆块:精确=4 -> idx_sales_product_id_sale_date 位图索引扫描(成本=0.00..4.45=3 宽度=0)(实际时间=0.045..0.045=4 循环=1)索引条件:((product_id = 408AND(sale_date = '2024-08-17'::date))
计划时间:0.265 毫秒
执行时间: 0.074 毫秒
(7 行)

哇!执行时间从 19.078 毫秒缩短至 0.074 毫秒,性能提高了近 275 倍。

部分索引

部分索引仅索引满足特定条件的数据子集,而不是覆盖表中的所有行。它们非常适合只频繁查询部分数据的情况,例如仅索引活跃用户或近期交易。通过定位特定的数据子集,部分索引可以减少存储需求并提高查询性能。

使用部分索引的优点

  • 部分索引仅覆盖表的一部分,与完整索引相比,存储成本较低。
  • 它们的尺寸较小,在插入、更新和删除过程中需要的维护时间和资源较少。
  • UPDATE 操作通常更快,因为部分索引不需要在每次更改时更新。

使用部分索引的缺点

  • 部分索引不涵盖所有数据,因此随着表大小的增加,非索引数据上的连接或过滤可能会导致性能下降。
  • 仅当索引子集被频繁查询时,部分索引才有用;否则,如果查询不符合索引条件,它们可能不会提高性能。

部分索引示例

让我们创建一个表来存储 COVID-19 数据。并在表中插入 300 万条虚拟记录。

如果不存在,则创建表 covid_data(id SERIAL PRIMARY KEY、国家 varchar(20)、标题 varchar(10)、名称 varchar(20)、接种疫苗 varchar(3));
CREATE TABLE 
ostgres=# INSERT INTO covid_data (country, title, names, vaccinated) 
postgres-# SELECT 
-- 从预定义列表中随机选择国家
(ARRAY['USA', 'Canada', 'UK', 'Germany', 'France', 'India', 'China', 'Brazil', 'Australia', 'Japan'])[floor(random() * 10 + 1)], 
-- 从预定义列表中随机选择头衔
(ARRAY['Mr.', 'Ms.', 'Dr.', 'Prof.'])[floor(random() * 4 + 1)], 
-- 从预定义列表中随机选择姓名
(ARRAY['John', 'Jane', 'Alex', 'Emily', 'Michael', 'Sarah', 'David', 'Laura', 'Robert', 'Linda'])[floor(random() * 10 + 1)], 
-- 随机疫苗接种状态(“是”或“否”)
CASE WHEN random() < 0.8 THEN '是' -- 80% 的可能性为“是” ELSE '否' -- 20% 的可能性为“否” 
END 
FROM generate_series(1, 3000000);

首先,让我们使用EXPLAIN ANALYZE运行SELECT查询来分析执行计划并获取结果。

postgres=# EXPLAIN ANALYZE SELECT * FROM covid_data WHERE vaccinated = '是' AND country = '英国' AND title = '教授';查询计划                                                           
--------------------------------------------------------------------------------------------------------------------------
收集(成本=1000.00..27738.89=1 宽度=174)(实际时间=0.361..450.847=59916 循环=1)计划的工人:2启动的工人:2 -> 对 covid_data 进行并行序列扫描(成本=0.00..26738.79=1 宽度=174)(实际时间=0.075..432.697=19972 循环=3)过滤器:(((vaccinated)::text = 'Yes'::textAND((country)::text = 'UK'::textAND((title)::text = 'Prof.'::text))过滤器删除的行数:980028
计划时间:0.096 毫秒
执行时间:456.062 毫秒
(8 行)

由于没有索引,因此使用了顺序扫描,并在456 毫秒内返回结果。

现在,让我们创建三个索引,每个索引用于 SELECT 查询中的列。

postgres=# 在 covid_data(vaccinated) 上创建索引 vaccinated_full_idx;
创建索引
postgres=# 在 covid_data(country) 上创建索引 country_full_idx;
创建索引
postgres=# 在 covid_data(title) 上创建索引 title_full_idx;
创建索引

现在,让我们再次运行相同的SELECT查询并检查执行时间是否减少。

postgres=# EXPLAIN ANALYZE SELECT * FROM covid_data WHERE vaccinated = '是' AND country = '英国' AND title = '教授';查询计划                                                                   
------------------------------------------------------------------------------------------------------------------------------------------------
对 covid_data 进行位图堆扫描(成本=495.29..499.31=1 宽度=174)(实际时间=100.977..229.152=59435 循环=1)重新检查条件:(((title)::text = 'Prof.'::textAND((country)::text = 'UK'::textAND((vaccinated)::text = 'Yes'::text))堆块:精确=19605 -> BitmapAnd(成本=495.29..495.29=1 宽度=0)(实际时间=97.916..97.917=0 循环=1-> 对 title_full_idx 进行位图索引扫描(成本=0.00..164.93=15000 宽度=0)(实际时间=23.191..23.192=749479 循环=1)索引条件:((title)::text = 'Prof.'::text-> country_full_idx 上的位图索引扫描(成本=0.00..164.93=15000 宽度=0)(实际时间=11.334..11.334=299158 循环=1)索引条件:((country)::text = 'UK'::text-> vaccinated_full_idx 上的位图索引扫描(成本=0.00..164.93=15000 宽度=0)(实际时间=62.001..62.001=2400565 循环=1)索引条件:((vaccinated)::text = '是'::文本)
计划时间:0.477 毫秒
执行时间:232.855 毫秒
(12 行)
postgres=# SELECT pg_size_pretty(pg_relation_size('title_full_idx')); 
pg_size_pretty  
---------------- 
20 MB ( 1 行) postgres=# SELECT pg_size_pretty(pg_relation_size ('country_full_idx')); pg_size_pretty ---------------- 20 MB(1 行) postgres=# SELECT pg_size_pretty( pg_relation_size ( ' 
vaccinated_full_idx 
')); pg_size_pretty  ---------------- 20 MB (1 行)

这次执行时间减少到232 毫秒,性能提升了1.9 倍。PostgreSQL 使用近60 MB来存储这些索引。

现在,让我们使用部分索引来看看是否可以同时优化速度和空间并取得更好的结果。

创建部分索引

postgres = # CREATE INDEX vaccinated_pa​​rtial_idx ON covid_data(vaccinated) WHERE vaccinated = '是' AND country = '英国' AND title = '教授';
创建索引

现在执行相同的 SELECT 查询

postgres=# EXPLAIN ANALYZE SELECT * FROM covid_data WHERE vaccinated = 'Yes' AND country = 'UK' AND title = 'Prof.';查询计划                                                                
--------------------------------------------------------------------------------------------------------------------------------------------------
使用 vaccinated_pa​​rtial_idx 对 covid_data 进行索引扫描(成本=0.29..8.30=1 宽度=174)(实际时间=0.023..79.981=60644 循环=1)
计划时间:0.237 毫秒
执行时间:83.855 毫秒
(3 行)
postgres=# SELECT pg_size_pretty(pg_relation_size('vaccinated_pa​​rtial_idx')); 
pg_size_pretty  
---------------- 
424 kB 
(1 行)

哇!通过部分索引,我们实现了5.4 倍的性能提升,并且大小减少了99.29%。
#PG证书#PG考试#postgresql初级#postgresql中级#postgresql高级

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/148974.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

BUG——IMX6ULL编译正点原子Linux内核报错

最初编译的是正点原子改过的Linux内核&#xff0c;可能是版本问题&#xff0c;一直报错&#xff0c;无法成功编译。然后换成NXP官方Linux内核6.6版本&#xff0c;初始编译虽然也报各种错&#xff0c;但都是缺少库或相关工具&#xff0c;全部安装后就可以成功编译出镜像了&#…

运营商二要素接口如何用PHP实现调用

一、什么是手机二要素&#xff1f; 运营商二要素又称手机二要素&#xff0c;运营商二要素核验&#xff0c;手机二要素核验&#xff0c;即传入姓名、手机号码&#xff0c;校验此两项是否一致。实时核验&#xff0c;返回校验结果&#xff01; 二、手机二要素适用哪些场景&#…

【逐行注释】MATLAB的程序,对比EKF(扩展卡尔曼滤波)和PF(粒子滤波)的滤波效果,附下载链接

文章目录 总述部分源代码运行结果扩展性 总述 本代码使用 M A T L A B MATLAB MATLAB实现了扩展卡尔曼滤波&#xff08; E K F EKF EKF&#xff09;和粒子滤波&#xff08; P F PF PF&#xff09;在状态估计中的对比分析。 主要功能包括&#xff1a; 参数设置&#xff1a;初始…

【apt-file命令详解:Linux下的包管理利器】

文章目录 前言一、apt-file命令简介二、安装apt-file三、apt-file命令的基本用法四、高级技巧五、总结 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&#xff01;&#x1f60a; &a…

基于SSM的“银发在线教育云平台”的设计与实现(源码+数据库+文档)

基于SSM的“银发在线教育云平台”的设计与实现&#xff08;源码数据库文档) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 首页页面图 健身养生详情页面 在线课堂界面 …

Intellij IDEA 通过数据库表生成带注解的Java实体类(lombok版)

前言&#xff1a;因为今天在写实体类的时候&#xff0c;发现表中的字段太多&#xff0c;而且又要加注解怕写错漏写&#xff0c;现在市面上也有许多插件&#xff0c;但是有些达不到代码简洁&#xff0c;需要修改。后来还是选择了采用groovy写了一个脚本编写&#xff0c;本来idea…

gitlab使用小结

GitLab 是一个基于 Git 的代码托管平台&#xff0c;提供了丰富的功能来管理代码仓库、CI/CD、项目管理等。以下是一些常用的 GitLab 命令和示例&#xff0c;帮助你更好地使用 GitLab。 1、 克隆仓库 克隆一个远程仓库到本地&#xff1a; git clone gitgitlab.example.com:us…

深圳mes制造系统的主要功能

深圳MES系统的主要功能包括以下几个方面&#xff1a; 生产计划管理&#xff1a;MES系统可以帮助企业制定生产计划&#xff0c;包括订单管理、生产排程、生产任务分配等&#xff0c;实现生产资源的合理配置和生产计划的优化。 生产过程控制&#xff1a;MES系统可以监控生产过程中…

SpringBoot技术栈的网上超市开发实践

2 系统开发技术 这部分内容主要介绍本系统使用的技术&#xff0c;包括使用的工具&#xff0c;编程的语言等内容。 2.1 Java语言 Java语言自公元1995年至今&#xff0c;已经超过25年了&#xff0c;依然在软件开发上面有很大的市场占有率。当年Sun公司发明Java就是为了发展一门跨…

局域网远程命令重启电脑

只要知道远程服务器的管理员密码和IP地址&#xff0c;在局域网中的任意一台机器上打开“命令提示符”窗口&#xff0c;运行以下命令&#xff1a; 1、获取远程服务器的管理员权限 net use IP地址 "管理员密码" /user:administrator 2、使用shutdown命令远程重启服务器…

32中的外部中断

一、理解中断 关于32的中断 中断就是给cpu一个信号&#xff0c;cpu收到这个对应的信号再进行指挥 最常用的就是按键 key1按下是咩意思key2呢这样 中断信号线CPU要和对应的元器件连接 二、中断代码 代码编写 所有的0脚对应中断寄存器0&#xff0c;以此类推 引脚为n …

Unity :单例模式 + MonoBehaviour 是什么体验?

单例模式 与 MonoBehaviour的冲突点 单例模式 MonoBehaviour 保持单例的快速解决方案 就是自己创建一个空对象&#xff0c;然后把脚本挂在上去就行了&#xff0c;之后你就别自己挂载该脚本就行了 一般写法 public class AgentMoNo : MonoBehaviour {private static AgentM…

Python编码系列—Python观察者模式:实现事件驱动架构的利器

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

ComfyUI新版本提升效率小技巧(建议收藏)

原文链接&#xff1a;建议收藏&#xff01;ComfyUI提升效率的小技巧&#xff0c;肯定有你不知道的 (chinaz.com) 本篇带来ComfyUI非常实用的9个小技巧&#xff0c;可以提升我们的ComfyUI工作效率&#xff0c;建议大家收藏起来哈 新版中文搜节点 点击设置 comfy→搜索框框架…

PHP判断微信或QQ访问

PHP判断微信或QQ访问 若是微信或者QQ打开&#xff0c;提示图会覆盖网页&#xff0c;但网页功能仍在运行&#xff01; <meta name"viewport" content"initial-scale1, maximum-scale1, user-scalableno, widthdevice-width"><style> .top-gui…

OpenCV目标检测(1)模板匹配函数matchTemplate()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将一个模板与重叠的图像区域进行比较。 该函数在图像中滑动&#xff0c;使用指定的方法将大小为 w h w \times h wh的重叠块与模板 templ 进行…

基于python+django+vue的旅游景点数据分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

【Canvas与诗词】铁马冰河入梦来

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>金红圈铁马冰河入梦来</title><style type"text/css&q…

【linux经典工具】strace-就十分钟你也能成为性能调优专家

strace 是什么 strace是一款功能强大的 Linux 进程监控和诊断工具。主要作用就是&#xff1a;用于调试程序、解决问题、拦截和记录系统调用以及跟踪正在运行的进程。它能输出了程序如何与系统交互的过程&#xff0c;尤其是在无法获取源代码的情况下&#xff08;那些开源工具、…

召回04 离散特征的处理

推荐系统会将一个id映射成一个向量 Qne-Hot编码 Embedding(嵌入)&#xff1a; 把每个类别映射成一个低维的稠密向量