PostgreSQL 联合索引生效条件

最近面试的时候,总会遇到一个问题

在 PostgreSQL 中,联合索引在什么条件下会生效?

特此记录~

前置信息

数据库版本

  • PostgreSQL 14.13, compiled by Visual C++ build 1941, 64-bit

建表语句

CREATE TABLE people (id SERIAL PRIMARY KEY,city VARCHAR(50),name VARCHAR(50),age INT
);CREATE INDEX idx_city_name_age ON people(city, name, age);-- 插入数据
INSERT INTO people (city, name, age) VALUES
('Beijing', 'Tom', 18),
('Beijing', 'Tom', 20),
('Beijing', 'Jerry', 18),
('Shanghai', 'Jerry', 22),
('Shanghai', 'Alice', 25),
('Guangzhou', 'Bob', 30);

查看索引是否命中

EXPLAIN ANALYZE SELECT * FROM people WHERE city = 'Beijing' AND name = 'Tom' AND age = 20;

结果

Index Scan using idx_city_name_age on people  (cost=0.15..8.17 rows=1 width=244) (actual time=0.012..0.013 rows=1 loops=1)Index Cond: (((city)::text = 'Beijing'::text) AND ((name)::text = 'Tom'::text) AND (age = 20))
Planning Time: 0.074 ms
Execution Time: 0.022 ms

我们可以清楚的看到索引命中了,那么改变一下 WHERE 条件呢,例如:

EXPLAIN ANALYZE SELECT * FROM people WHERE city = 'Beijing';
EXPLAIN ANALYZE SELECT * FROM people WHERE name = 'Tom';
EXPLAIN ANALYZE SELECT * FROM people WHERE age = 20;
EXPLAIN ANALYZE SELECT * FROM people WHERE name = 'Tom' and age = 20;
EXPLAIN ANALYZE SELECT * FROM people WHERE city = 'Beijing' and name = 'Tom';
EXPLAIN ANALYZE SELECT * FROM people WHERE city = 'Beijing' and age = 20;

分别执行一下,查看结果

Bitmap Heap Scan on people  (cost=4.16..9.50 rows=2 width=244) (actual time=0.014..0.014 rows=3 loops=1)Recheck Cond: ((city)::text = 'Beijing'::text)Heap Blocks: exact=1->  Bitmap Index Scan on idx_city_name_age  (cost=0.00..4.16 rows=2 width=0) (actual time=0.011..0.011 rows=3 loops=1)Index Cond: ((city)::text = 'Beijing'::text)
Planning Time: 0.056 ms
Execution Time: 0.031 ms-------------------------------------------------------------------------------
Seq Scan on people  (cost=0.00..13.75 rows=2 width=244) (actual time=0.009..0.010 rows=2 loops=1)Filter: ((name)::text = 'Tom'::text)Rows Removed by Filter: 4
Planning Time: 0.060 ms
Execution Time: 0.020 ms-------------------------------------------------------------------------------
Seq Scan on people  (cost=0.00..13.75 rows=2 width=244) (actual time=0.008..0.009 rows=1 loops=1)Filter: (age = 20)Rows Removed by Filter: 5
Planning Time: 0.054 ms
Execution Time: 0.017 ms-------------------------------------------------------------------------------
Seq Scan on people  (cost=0.00..14.50 rows=1 width=244) (actual time=0.011..0.012 rows=1 loops=1)Filter: (((name)::text = 'Tom'::text) AND (age = 20))Rows Removed by Filter: 5
Planning Time: 0.056 ms
Execution Time: 0.020 ms-------------------------------------------------------------------------------
Index Scan using idx_city_name_age on people  (cost=0.15..8.17 rows=1 width=244) (actual time=0.015..0.016 rows=2 loops=1)Index Cond: (((city)::text = 'Beijing'::text) AND ((name)::text = 'Tom'::text))
Planning Time: 0.057 ms
Execution Time: 0.026 ms-------------------------------------------------------------------------------
Index Scan using idx_city_name_age on people  (cost=0.15..8.18 rows=1 width=244) (actual time=0.018..0.019 rows=1 loops=1)Index Cond: (((city)::text = 'Beijing'::text) AND (age = 20))
Planning Time: 0.062 ms
Execution Time: 0.031 ms

查看结果,我们发现,WHERE条件后面带上 city字段的 SQL 语句全部走了索引,其余字段全表扫描。

看到这儿,可能可以得出结论,PG 数据库联合索引遵循最左匹配原则,只有最左边的字段存在才能命中索引。

这里才几条数据,让我们增加 people 表中的数据

INSERT INTO people (city, name, age)
SELECT-- 随机分配 3 个城市CASE (random()*3)::intWHEN 0 THEN 'Beijing'WHEN 1 THEN 'Shanghai'ELSE 'Guangzhou'END,-- 随机分配 10 个名字CASE (random()*10)::intWHEN 0 THEN 'Tom'WHEN 1 THEN 'Jerry'WHEN 2 THEN 'Alice'WHEN 3 THEN 'Bob'WHEN 4 THEN 'David'WHEN 5 THEN 'Eva'WHEN 6 THEN 'John'WHEN 7 THEN 'Lily'WHEN 8 THEN 'Lucy'ELSE 'Mike'END,(random()*100)::int  -- 年龄 0~100
FROM generate_series(1, 100000);

这行 SQL 语句为 people 表增加了十万条数据,让我们再试试没有 city字段的查询语句

EXPLAIN ANALYZE SELECT * FROM people WHERE age = 18 and name = 'David';

执行结果

Bitmap Heap Scan on people  (cost=1556.38..1836.90 rows=107 width=22) (actual time=0.485..0.532 rows=80 loops=1)Recheck Cond: (((name)::text = 'David'::text) AND (age = 18))Heap Blocks: exact=78->  Bitmap Index Scan on idx_city_name_age  (cost=0.00..1556.35 rows=107 width=0) (actual time=0.477..0.477 rows=80 loops=1)Index Cond: (((name)::text = 'David'::text) AND (age = 18))
Planning Time: 0.856 ms
Execution Time: 0.549 ms

我们看到没有 city 字段,还是走了索引。但是似乎这种方式不是高效的方式,PG 数据库综合考虑还是走了索引,别的情况下可能不会走索引。

但是单独的非最左索引字段肯定不走索引,例如:

EXPLAIN ANALYZE SELECT * FROM people WHERE age = 18;
EXPLAIN ANALYZE SELECT * FROM people WHERE name = 'David';

结果

Seq Scan on people  (cost=0.00..1887.08 rows=1050 width=22) (actual time=0.009..6.824 rows=1039 loops=1)Filter: (age = 18)Rows Removed by Filter: 98967
Planning Time: 0.072 ms
Execution Time: 6.857 ms----------------------------------------------------------------
Seq Scan on people  (cost=0.00..1887.08 rows=10204 width=22) (actual time=0.014..6.997 rows=10041 loops=1)Filter: ((name)::text = 'David'::text)Rows Removed by Filter: 89965
Planning Time: 0.057 ms
Execution Time: 7.207 ms

全表扫描,没有走索引

总结

总的来说,Postgres 数据库联合索引生效条件遵循最左匹配原则。

在本例中,也就是说 city字段存在于 where条件的后面,才能高效的使用索引,如果没有 city字段,可能也会命中索引,但是是不高效的,当三个联合索引字段都存在时,这时是最高效的查询语句。

另外,查询字段在 WHERE 条件后面的顺序是不妨碍索引是否命中的,PG 优化器会识别优化。

你对 Postgre 数据库的联合索引有了解吗?你是否知道何种情况下 PG 数据库会高效的命中索引,可以留下你的评论,我们一起讨论。

如有错误,请指正~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot项目里面发起http请求的几种方法

在Spring Boot项目中发起HTTP请求的方法 在Spring Boot项目中,有几种常用的方式可以发起HTTP请求,以下是主要的几种方法: 1. 使用RestTemplate (Spring 5之前的主流方式) // 需要先注入RestTemplate Autowired private RestTemplate restT…

《Python星球日记》 第90天:微调的概念以及如何微调大模型?

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、微调原理1. 什么是大模型微调?2. 为什么需要微调?3. 微调的基本流程4. 微调策略分类二、LoRA(Low-Rank Adaptation)技术详解1. LoRA的核…

机器学习-人与机器生数据的区分模型测试 - 模型融合与检验

模型融合 # 先用普通Pipeline训练 from sklearn.pipeline import Pipeline#from sklearn2pmml.pipeline import PMMLPipeline train_pipe Pipeline([(scaler, StandardScaler()),(ensemble, VotingClassifier(estimators[(rf, RandomForestClassifier(n_estimators200, max_de…

怎样免费开发部署自己的网站?

要免费开发自己的网站,您可以根据自己的技术水平和需求选择以下两种主要方式: 零基础用户:建议使用如WordPress.com、Weebly、Strikingly等平台,快速搭建网站。 有一定技术基础的用户:可选择自行开发网站,…

调用百度云API机器翻译

新建Python文件,叫 text_translator.py 输入 import requests import jsonAPI_KEY "glYiYVF2dSc7EQ8n78VDRCpa" # 替换为自己的API Key SECRET_KEY "kUlhze8OQZ7xbVRp" # 替换为自己的Secret Keydef main():# 选择翻译方向while True:di…

OpenAI与微软洽谈新融资及IPO,Instagram因TikTok流失四成用户

OpenAI与微软洽谈新融资及IPO 据悉,OpenAI 正与微软洽谈新融资及筹备 IPO,关键问题是微软在 OpenAI 重组后的股权比例。微软已投资超 130 亿美元,双方修订 2019 年合同,微软拟弃部分股权换新技术访问权。OpenAI 上周放弃了有争议转…

git工具使用详细教程-------命令行和TortoiseGit图形化

下载 git下载地址:https://git-scm.com/downloads TortoiseGit(图形化工具)下载地址:https://tortoisegit.org/download/ 认识git结构 工作区:存放代码的地方 暂存区:临时存储,将工作区的代码…

构建RAG混合开发---PythonAI+JavaEE+Vue.js前端的实践

7GB显存如何部署bf16精度的DeepSeek-R1 70B大模型?-CSDN博客 服务容错治理框架resilience4j&sentinel基础应用---微服务的限流/熔断/降级解决方案-CSDN博客 conda管理python环境-CSDN博客 快速搭建对象存储服务 - Minio,并解决临时地址暴露ip、短…

【Java ee初阶】jvm(3)

一、双亲委派机制(类加载机制中,最经常考到的问题) 类加载的第一个环节中,根据类的全限定类名(包名类名)找到对应的.class文件的过程。 JVM中进行类加载的操作,需要以来内部的模块“类加载器”…

wps excel将表格输出pdf时所有列在一张纸上

记录:wps excel将表格输出pdf时所有列在一张纸上 1,调整缩放比例,或选择将所有列打印在一页 2,将表格的所有铺满到这套虚线

分布式微服务系统架构第134集:笔记1运维服务器经验,高并发,大数据量系统

加群联系作者vx:xiaoda0423 仓库地址:https://webvueblog.github.io/JavaPlusDoc/ https://1024bat.cn/ https://github.com/webVueBlog/fastapi_plus https://webvueblog.github.io/JavaPlusDoc/ ✅ 一、查看端口是否被占用的常用命令 1️⃣ lsof 命令&…

IS-IS 中间系统到中间系统

前言: 中间系统到中间系统IS-IS(Intermediate System to Intermediate System)属于内部网关协议IGP(Interior Gateway Protocol),用于自治系统内部 IS-IS也是一种链路状态协议,使用最短路径优先…

前端安全:XSS、CSRF 防御与最佳实践

引言 随着互联网应用的普及,前端安全问题日益凸显。作为开发者,了解并防范常见的安全威胁至关重要。本文将深入探讨两种最常见的前端安全威胁:跨站脚本攻击(XSS)和跨站请求伪造(CSRF)&#xff…

uniapp 弹窗封装(上、下、左、右、中五个方位)

无脑复制即可&#xff01;&#xff01;&#xff01; <template><view><viewv-if"mask"class"tui-drawer-mask":class"{ tui-drawer-mask_show: visible }":style"{ zIndex: maskZIndex }"tap"handleMaskClick&qu…

Axure制作可视化大屏动态滚动列表教程

在可视化大屏设计中&#xff0c;动态滚动列表是一种常见且实用的展示方式&#xff0c;能够有效地展示大量信息。本文将详细介绍如何使用Axure制作一个动态滚动的列表展示模块。 一、准备工作 打开Axure软件&#xff1a;确保你已经安装并打开了Axure RP软件。创建新项目&#x…

零基础玩转Apache Superset可视化部署

根据官方Quick Start Guide&#xff0c;你可以按照以下步骤进行部署&#xff1a; 1. 确认环境2. 获取代码3. 获取官方最新代码4. 启动服务5. 访问Superset Web界面6. 接入数据源 前提条件&#xff1a; dockerdocker compose 1. 确认环境 安装Docker和Docker Compose 确保你…

服务器数据恢复—XFS文件系统分区消失的数据恢复案例

服务器数据恢复环境&故障&#xff1a; 服务器上有一组由raid卡组建的raid5磁盘阵列。上层安装linux才做系统&#xff0c;采用XFS文件系统&#xff0c;划分了3个分区。 管理员将服务器的操作系统重装后&#xff0c;发现服务器上的分区发生了改变&#xff1a;一个分区消失&am…

2025/5/18

继续研究一下大佬的RAG项目。开始我的碎碎念。 RAG可以分成两部分&#xff1a;一个是问答&#xff0c;一个是数据处理。 问答是人提问&#xff0c;然后查数据库&#xff0c;把查的东西用大模型组织成人话&#xff0c;回答人的提问。 数据处理是把当下知识库里的东西&#xf…

在 Vue 中插入 B 站视频

前言 在 Vue 项目中&#xff0c;有时我们需要嵌入 B 站视频来丰富页面内容&#xff0c;为用户提供更直观的信息展示。本文将详细介绍在 Vue 中插入 B 站视频的多种方法。 使用<iframe>标签直接嵌入,<iframe>标签是一种简单直接的方式&#xff0c;可将 B 站视频嵌…

OpenCv高阶(八)——摄像头调用、摄像头OCR

文章目录 前言一、摄像头调用通用方法1、导入必要的库2、创建摄像头接口 二、摄像头OCR1.引入库2、定义函数&#xff08;1&#xff09;定义显示opencv显示函数&#xff08;2&#xff09;保持宽高比的缩放函数&#xff08;3&#xff09;坐标点排序函数&#xff08;4&#xff09;…