数据库索引设计原则

news2024/9/22 23:16:28

在这里插入图片描述

1. 概述

索引是优化数据库性能最重要的工具之一。但是,创建过多的索引或索引错误的列也会对性能产生负面影响。因此,在设计索引时遵循一定的原则很重要

2. 原则A - 根据工作负载创建索引

创建高效索引最重要的原则是根据您的工作负载而不是表结构创建索引。索引的目的是提高数据库中操作的效率,而针对数据库执行的 SQL 语句构成了数据库的工作负载。因此,任何其他不从工作负载出发的索引创建方法都是​​错误的

在为某个工作负载构建一组索引时,我们需要考虑该工作负载的以下特征

  • SQL 类型:在 OLTP 场景中,用户频繁插入新数据和修改现有数据,多个索引可能会对性能产生负面影响。建议创建满足索引需求的最小索引数量。在查询占主导地位的 OLAP 场景中,您可以添加更多索引,每个索引可以有多个列,甚至可以创建函数索引和条件索引。
  • SQL 频率:应该为最常用的查询创建索引。通过为这些查询创建最佳索引,可以最大限度地提高系统的整体性能。
  • SQL 查询的重要性:查询越重要,您就越希望通过创建索引来优化其性能。
  • SQL 查询本身的结构。

在这里插入图片描述

3. 原则B - 根据SQL结构创建索引

索引的作用如下:

  • 快速定位数据
  • 避免排序
  • 避免表查找

3.1 快速定位

索引可以通过匹配查询条件来快速定位数据,查询条件可以是WHERE子句HAVING子句,也可以是ON子句,索引与条件的匹配原则遵循最左前缀匹配原则。

3.1.1 最左前缀匹配原则

最左前缀匹配原则是指当相等的查询条件准确匹配索引最左边的连续列或某几列时,该列可以用来匹配索引。当遇到范围查询(>、<、between、like)时,匹配停止,但范围条件仍然匹配。

对于组合索引来说lineitem (l_shipdate, l_quantity),下面前两个SQL满足最左前缀匹配原则,可以使用索引,最后一个不满足最左前缀匹配原则,无法使用索引。

select * from lineitem where l_shipdate = date '2021-12-01'; -- index can be used
select * from lineitem where l_shipdate = date '2021-12-01' and l_quantity = 100; -- index can be used
select * from lineitem where l_quantity = 100; -- The index cannot be used

这三个SQL查询的执行计划如下:

-> Index lookup on lineitem using lidx (L_QUANTITY=100.00, L_SHIPDATE=DATE'2021-12-01') (cost=0.35 rows=1)

-> Index lookup on lineitem using lidx (L_QUANTITY=100.00, L_SHIPDATE=DATE'2021-12-01') (cost=0.35 rows=1)

-> Filter: (lineitem.L_QUANTITY = 100.00) (cost=15208.05 rows=49486)
     -> Table scan on lineitem (cost=15208.05 rows=148473)

除了最左前缀原则外,创建复合索引时还应考虑不同值的数量(基数)来决定索引字段的顺序。基数较高的字段应放在第一位。

3.1.2 平等条件

单表平等条件

  • COL = ‘A’
  • COL IN (‘A’)

表连接中的相等条件,当一个表作为驱动表时,相等连接条件也可以认为是使用相等条件进行索引匹配。

T1.COL = T2.COL

select * from orders, lineitem where o_orderkey = l_orderkey;

上述查询的执行计划

-> Nested loop inner join (cost=484815.77 rows=1326500)
    -> Table scan on orders (cost=20540.71 rows=200128)
    -> Index lookup on lineitem using lineitem_idx(L_ORDERKEY=orders.O_ORDERKEY) (cost=1.66 rows=7)

由于最左匹配原则,遵循范围条件的索引列无法利用索引。

3.2 避免排序

对于 B+ 树索引,由于是按照索引键排序的,因此在 SQL 查询中可以使用 B+ 树来避免排序。涉及的 SQL 结构主要包括:

  • GROUP BY
  • ORDER BY
  • DISTINCT
  • PARTITION BY… ORDER BY…

lshipdate_idx假设我们有如下索引

create index lshipdate_idx on lineitem(l_shipdate);

您可以看到以下 SQL 的执行计划利用lshipdate_idx索引来避免排序。

  • SQL1 (ORDER BY)
  select * from lineitem order by l_shipdate limit 10;

SQL1 的执行计划

  -> Limit: 10 row(s) (cost=0.02 rows=10)
      -> Index scan on lineitem using lshipdate_idx (cost=0.02 rows=10)
  • SQL2(GROUP BY)
  select l_shipdate, sum(l_quantity) as sum_qty from lineitem group by l_shipdate;

SQL2 的执行计划

  -> Group aggregate: sum(lineitem.L_QUANTITY) (cost=30055.35 rows=148473)
      -> Index scan on lineitem using lshipdate_idx (cost=15208.05 rows=148473)
  • SQL3(DISTINCT)
  select DISTINCT l_shipdate from lineitem;

SQL3 的执行计划

  -> Covering index skip scan for deduplication on lineitem using lshipdate_idx (cost=4954.90 rows=15973)
  • SQL4(PARTITION BY… ORDER BY…)
  select rank() over (partition by L_SHIPDATE order by L_ORDERKEY) from lineitem;

SQL4 的执行计划

  WindowAgg (cost=0.29..545.28 rows=10000 width=28)
  -> Index Only Scan using lshipdate_idx on lineitem (cost=0.29..370.28 rows=10000 width=20)

此部分重要的笔记

  1. 对于分组和重复数据删除,顺序并不重要。
  2. 对于排序来说,排序列的顺序需要与索引列的顺序相匹配,否则无法使用索引来避免排序。
  3. 如果排序和分组同时出现,则排序列需要先出现。
    例如,对于以下 SQL 语句:
select l_shipdate, l_orderkey, sum(l_quantity) as sum_qty from lineitem 
group by l_shipdate, l_orderkey order by l_orderkey;
  • 场景 1:在 上创建索引(l_shipdate, l_orderkey),使用索引访问,并要求排序,耗时为486.526。
-> Sort: lineitem.L_ORDERKEY (actual time=479.465..486.526 rows=149413 loops=1)
     -> Stream results (cost=30055.35 rows=148473) (actual time=0.175..423.447 rows=149413 loops=1)
         -> Group aggregate: sum(lineitem.L_QUANTITY) (cost=30055.35 rows=148473) (actual time=0.170..394.978 rows=149413 loops=1)
             -> Index scan on lineitem using lshipdate_idx2 (cost=15208.05 rows=148473) (actual time=0.145..359.567 rows=149814 loops=1)
  • 场景 2:在 上创建索引(l_orderkey,l_shipdate),使用索引访问,并避免排序,耗时为228.401。
-> Group aggregate: sum(lineitem.L_QUANTITY)  (cost=30055.35 rows=148473) (actual time=0.067..228.401 rows=149413 loops=1)
    -> Index scan on lineitem using lshipdate_idx3  (cost=15208.05 rows=148473) (actual time=0.052..194.479 rows=149814 loops=1)

3.3 避免表查找

当查询的所有列都在索引列中时,数据库只需要访问索引就可以获得所需的数据,避免了查表。在某些场景下,这可以大大提高查询效率。

对于以下 SQL 语句:

select l_shipdate, l_orderkey,  sum(l_quantity) as sum_qty from lineitem group by l_orderkey,l_shipdate;

(l_orderkey,l_shipdate) 上的索引不包括l_quantity,需要进行表查找,耗时为 194.875。

-> Group aggregate: sum(lineitem.L_QUANTITY)  (cost=30055.35 rows=148473) (actual time=0.044..194.875 rows=149413 loops=1)
    -> Index scan on lineitem using lshipdate_idx3  (cost=15208.05 rows=148473) (actual time=0.034..159.863 rows=149814 loops=1)

(l_orderkey,l_shipdate,l_quantity) 上的索引包括l_quantity,不需要表查找,耗时为 113.433,性能提升约 71.8%。

-> Group aggregate: sum(lineitem.L_QUANTITY)  (cost=30055.35 rows=148473) (actual time=0.035..113.433 rows=149413 loops=1)
    -> Covering index scan on lineitem using lshipdate_idx4  (cost=15208.05 rows=148473) (actual time=0.026..82.266 rows=149814 loops=1)

在这里插入图片描述

4. 原则C - 索引设计的约束

4.1 设计索引时,重要的是考虑以下约束

  1. 每个表的最大索引数:创建过多的索引会对写入性能产生负面影响,因为每次插入或更新表时都必须更新索引。因此,限制每个表的索引数量非常重要。
  2. 每个索引的最大列数:创建包含太多列的索引也会对性能产生负面影响,因为索引可能会变得太大而无法高效运行。因此,限制每个索引的列数非常重要。
  3. 磁盘空间使用情况:索引会占用大量磁盘空间。因此,在设计索引时考虑可用磁盘空间量非常重要。

4.2 设计和维护这些约束的索引,可以使用以下方法

  1. 索引选择:可以在最重要的 SQL 语句或最常用的查询上提供索引。
  2. 索引列的选择:应根据列的单值选择性评估,在过滤效果最好的列上建立索引,避免在经常更新的列上建立索引。
  3. 索引合并:通过在复合索引中按正确的顺序设计列,可以使用一个索引来加速多个查询。
  4. 索引删除:可以定期删除未使用的索引以释放磁盘空间并减少维护开销。

5. 总结

综上所述,索引的创建过程可以抽象为在上述约束条件下定义索引的收益,通过启发式算法计算出在特定约束条件下,整体工作负载收益最大的索引集,这也是PawSQL索引引擎的内在逻辑

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

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

相关文章

数据库连接池的深入学习

为什么需要数据库连接池&#xff1f; 正常操作数据库需要对其进行连接&#xff0c;访问数据库&#xff0c;执行sql语句&#xff0c;断开连接。 创建数据库连接是一个昂贵的过程&#xff0c;在高并发的情况下&#xff0c;频繁的创建数据库的连接可能会导致数据库宕机。 有了连…

Leetcode JAVA刷刷站(8)字符串转换整数

一、题目概述 二、思路方向 要实现这个功能&#xff0c;我们可以遵循以下步骤来编写 myAtoi 函数&#xff1a; 去除前导空格&#xff1a;使用循环或字符串的 trim() 方法&#xff08;虽然直接操作字符串更高效的方式是使用循环&#xff09;。检查符号&#xff1a;记录第一个非…

TGANet部分复现

Kvasir-SEG复现结果 M e t h o d m I o U m D S C R e c a l l P r e c i s i o n F 2 P r a N e t − − − − − − 0.9663704860609511 − − T G A N e t 0.8331 0.8982 0.9132 − − 0.9029 \begin{array}{lccccr} Method&mIoU&mDSC&Recall&Precision&a…

5、Linux : 网络相关

OSI七层网络模型 TCP/IP四层 概念模型 对应网络协议 应用层&#xff08;Application&#xff09; HTTP、TFTP, FTP, NFS, WAIS、 表示层&#xff08;Presentation&#xff09; 应用层 Telnet, Rlogin, SNMP, Gopher 会话层&#xff08;Session&#xff09; SMTP…

ICETEK-DM6437-AICOM——CPU定时器及直流电机控制中断控制

一、设计目的&#xff1a; 1.1 CPU定时器程序设计&#xff1b; 1.2 2直流电机程序设计&#xff1b; 1.3 外中断。 二、设计原理&#xff1a; 2.1 定时器的控制&#xff1a; 在DM6437&#xff08;是一种数字信号处理器&#xff0c;DSP&#xff09;上使用其内部定时器和中断来…

设计模式-动态代理模式

目录 什么是代理模式&#xff1f; 为什么要用代理模式&#xff1f; 有哪几种代理模式&#xff1f; 动态代理&#xff08;jdk自带&#xff09;&#xff1a; 动态代理&#xff08;第三方库-cglib&#xff09;&#xff1a; 什么是代理模式&#xff1f; 代理模式给某一个对象提供…

Windows10不能直接拖拽文件到微信或者钉钉的解决办法【玖毅网】

不知道从何时起,微信、QQ和钉钉等相关软件,无法拖拽文件到对话窗口,拖拽的时候显示一个红色图标,可能是上次更新win之后导致的,所以嘛,系统真的不能设置自动更新,说不准哪些更新就把原设置覆盖或者关闭了,哎,吃一堑长一智吧,赶紧关闭自动更新,emmmm我在说我自己啊。…

日撸Java三百行(day17:链队列)

目录 一、队列基础知识 1.队列的概念 2.队列的实现 二、代码实现 1.链队列创建 2.链队列遍历 3.入队 4.出队 5.数据测试 6.完整的程序代码 总结 一、队列基础知识 1.队列的概念 今天我们继续学习另一个常见的数据结构——队列。和栈一样&#xff0c;队列也是一种操…

零基础5分钟上手谷歌云GCP核心云开发技能 - 利用语音AI服务搭建应用

简介&#xff1a; 欢迎来到小李哥全新谷歌云GCP云计算知识学习系列&#xff0c;适用于任何无云计算或者谷歌云技术背景的开发者&#xff0c;让大家零基础5分钟通过这篇文章就能完全学会谷歌云一个经典的服务开发架构方案。 我将每天介绍一个基于全球三大云计算平台&#xff0…

arcgis(shp)注记转CAD(dwg)文字

arcgis&#xff08;shp&#xff09;注记转CAD&#xff08;dwg&#xff09;文字方法如下&#xff1a; 1、添加shp文件&#xff0c;标注要素&#xff0c;然后选标注转注记 2、 点击文件夹图标打开文件夹&#xff0c;选择保存路径。&#xff08;提前需新建好文件地理数据库、数据…

Arm Linux 设置系统日期时间的方法

一、设置系统日期时间的方法 1.命令行工具 date 命令&#xff1a;是Linux系统中用于查看和设置系统时间的常用命令行工具。通过date -s选项&#xff0c;可以手动设置系统时间。 sudo date -s "YYYY-MM-DD HH:MM:SS"hwclock 命令&#xff1a;用于查询和设置硬件时钟…

8月8日复习内容(基础的文件IO操作)

man手册 主要分为以下几个章节&#xff1a; User Commands&#xff08;用户命令&#xff09;&#xff1a;这一章节包含了普通用户&#xff08;非root用户&#xff09;可以执行的命令。这些命令通常用于日常的文件管理、文本编辑、程序执行等任务。 System Calls&#xff08;系…

【JavaEE初阶】常见的锁策略及synchronized实现原理

目录 &#x1f333; 常见的锁策略 &#x1f6a9; 乐观锁 vs 悲观锁 &#x1f6a9; 重量级锁 vs 轻量级锁 &#x1f6a9; 自旋锁 vs 挂起等待锁 &#x1f6a9; 可重入锁 vs 不可重入锁 &#x1f6a9; 公平锁 vs 非公平锁 &#x1f6a9; 互斥锁 vs 读写锁 &#x1f384; …

2024年8月8日(python基础)

一、检查并配置python环境&#xff08;python2内置&#xff09; 1、检测是否安装 [rootlocalhost ~]# yum list installed| grep python [rootlocalhost ~]# yum -y install epel-release 2、安装python3 [rootlocalhost ~]# yum -y install python3 最新版3.12可以使用源码安…

数据结构.

1:基本大纲 数据结构、算法线性表&#xff1a;顺序表、链表、栈、队列树&#xff1a;二叉树、遍历、创建查询方法、排序方式 2:数据结构&#xff08;逻辑结构&#xff0c;存储结构&#xff0c;操作&#xff08;数据的运算&#xff09;&#xff09; 2.1&#xff1a;数据&#xf…

RabbitMQ面试题汇总

RabbitMQ面试题 一、RabbitMQ基础1. 什么是RabbitMQ&#xff0c;它的基本架构是怎样的&#xff1f;2. RabbitMQ支持哪些协议&#xff1f;3. 说一下AMQP协议&#xff1f;4. 为什么要使用RabbitMQ&#xff1f;5. MQ的应用场景有哪些&#xff1f;6. 解耦、异步、削峰是什么&#x…

【Linux之·工程构建·Cmake】

系列文章目录 文章目录 前言一、概述二、CMake的基本概念2.1 CMake的工作原理和基本组成部分2.2 CMakeLists.txt文件的结构和语法2.2.1 变量操作2.2.2 注释2.2.3 日志2.2.4 宏定义 2.3 CMakeLists.txt文件的作用 三、CMake的常用命令和变量3.1 常用的CMake命令和变量3.1.1 字符…

多尺度病理图像纹理特征作为肺腺癌预后预测的新指标|文献精读·24-08-09

小罗碎碎念 这一期推文分享的文献是2022年发表于 Journal of Translational Medicine 的一篇文章&#xff0c;目前IF6.1。 这篇文章值得刚入门病理AI领域的老师/同学仔细研读&#xff0c;因为思路清晰&#xff0c;该讲到的流程基本都涉及了&#xff0c;详细讲述了病理图像的各种…

PyTorch基于深度神经网络的语音情绪识别

【图书推荐】《PyTorch语音识别实战》-CSDN博客 《PyTorch语音识别实战&#xff08;人工智能技术丛书&#xff09;》(王晓华)【摘要 书评 试读】- 京东图书 (jd.com) 情绪数据的获取与标签的说明 首先是语音情绪数据集的下载&#xff0c;在这里使用瑞尔森情感语音和歌曲视听数…

动态规划求解最小斯坦纳树(证了一天两夜)

最小斯坦纳树 给定点的“最小生成树”问题。 背景 给定无向连通图 G ( V , E ) G(V,E) G(V,E)&#xff0c;给出包含 k k k 个结点的点集 S S S&#xff0c;包含点集 S S S 的连通图被称作 斯坦纳树。但我们关注的是如何求出包含点集 S S S 的最小连通图 G ′ ( V ′ ,…