MySQL之创建高性能的索引(五)

创建高性能的索引

多列索引

很多人对多列索引的理解都不够。一个常见的错误就是,为每个列创建独立的索引,或者按照错误的顺序创建多列索引。先来看第一个问题,为每个列创建独立的索引,从SHOW CREATE TABLE总很容易看到这种情况:

CREATE TABLE t (
c1 INT,
c2 INT ,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);

这种索引策略,一般是由于人们听到一些专家诸如"把WHERE条件里面的列都建上索引"这样模糊的建议导致的.实际上这个建议是非常错误的。这样一来最好的情况也只能是一星索引,其性能必去真正最优的索引可能差几个数量级。有时如果无法设计一个三星索引,那么不如忽略掉WHERE子句,集中精力优化索引列的顺序,或者创建一个全覆盖索引。在多个列上建立独立的单列索引大部分情况下并不能提高MySQL的查询性能。MySQL5.0和更新版本引入了一种"索引合并"(index merge)的策略,一定程度上可以使用表上的多个单列索引来定位指定的行。更早版本的MySQL只能使用其中某一个单列索引,然而这种情况没有哪一个独立的单列索引是非常有效的。例如,表fime_actor在字典fim_id和actor_id上各有一个单列索引。但对于下面的这个查询WHERE条件,这两个单列索引都不是好的选择:

CREATE TABLE t (
c1 INT,
c2 INT ,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);

在老的MySQL版本中,MySQL对这个查询会使用全表扫描。除非改写成如下的两个查询UNION的方式:

mysql>  SELECT film_id,actor_id FROM film_actor WHERE actor_id = 1
UNION ALL
SELECT film_id,actor_id FROM film_actor WHERE film_id =1 AND actor_id <>1;

但在MySQL5.0和更新的版本中,查询能够同时使用这两个单列索引进行扫描,并将结果进行合并。这种算法有三个变种:OR条件的联合(union),AND条件的相交(intersection),组合前两种情况的联合及相交。下面的查询就是使用了两个索引扫描的联合,通过EXPLAIN中的Extra列可以看到这点:

mysql> EXPLAIN SELECT film_id,actor_id FROM film_actor WHERE actor_id = 1 OR film_id =1\G
*************************** 1. row ***************************id: 1select_type: SIMPLEtable: film_actorpartitions: NULLtype: index_merge
possible_keys: PRIMARY,idx_fk_film_idkey: PRIMARY,idx_fk_film_idkey_len: 2,2ref: NULLrows: 29filtered: 100.00Extra: Using union(PRIMARY,idx_fk_film_id); Using where
1 row in set, 1 warning (0.00 sec)

MySQL会使用这类基数优化复杂查询,所以在某些语句的Extra列中还可以看到嵌套操作。

索引合并策略有时候是一种优化的结果,但实际上更多时候说明了表上的索引建的很糟糕:

  • 1.当出现服务器对多个索引做相交操作时(通常有多个AND条件),通常意味着需要一个包含所有相关列的多列索引,而不是多个独立的单列索引
  • 2.当服务器需要对多个索引做联合操作时(通常有多个OR条件)通常需要耗费大量CPU和内存资源在算法的缓存、排序和合并操作上。特别是当其中有些索引的选择性不高,需要合并扫描返回的大量数据的时候
  • 3.更重要的是,优化器不会把这些计算到"查询成本"(cost)中,优化器只关心随机页面读取。这会使得查询的成本被"低估",导致该执行计划还不如直接走全表扫描。这样做不但会消耗更多的CPU和内存资源,还可能会影响查询的并发性,但如果是单独运行这样的查询则往往会忽略对并发性的影响。通常来说,还不如像在MySQL4.1或者更早的时代一样,将查询改写成UNION的方式往往更好

如果在中看到有索引合并,应该好好检查一下查询和表的结构,看是不是已经是最优的。可以通过参数optimizer_switch来关闭索引合并功能,也可以使用IGNORE INDEX提示让优化器忽略掉某些索引

选择合适的索引列顺序

我们遇到最容易引起困惑的问题就是索引列的顺序。正确的顺序依赖于使用该索引的查询,并且同时需要考虑如何更好地满足排序和分组的需要(以B-Tree索引为例)。在一个多列B-Tree索引中,索引列的顺序意味着索引首先按照最左列进行排序,其次是第二列,等等。所以索引可以按照升序或者降序进行扫描,以满足精确符合列顺序的ORDER BY 、GROUP BY和DISTINCT等子句的查询需求。所以多列索引的列顺序至关重要。在Lahdenmaki和Leach的"三星索引"系统中,列顺序也决定了一个索引是否能够成为一个真正的"三星索引".对于如何选择索引的列顺序有一个经验法则:将选择性最高的列放到索引最前列。这个建议有用吗?在某些场景可能有帮助,但通常不如避免随机IO和排序那么重要,考虑问题需要更全面(场景不同则选择不同,没有一个放之四海而皆准的法则。这里只是说明,这个经验法则可能没有你想象的重要)。当不需要考虑排序和分组时,将选择性最高的列放在前面通常是很好的,这时候索引的作用只是用于优化WHERE条件的查找。在这种情况下,这样设计的索引确实能够最快地过滤出需要的行,对于在WHERE子句中只适用了索引部分前缀列的查询来说选择性也更高。然而,性能不只是依赖于所有索引列的选择性(整体基数),也和查询条件的具体值有关,也就是和值的分布有关,可能需要根据那些运行频率最高的查询来调整索引列的顺序,让这种情况下索引的选择性最高。以下面的查询为例:

mysql> SELECT * FROM payment WHERE staff_id = 2 AND customer_id =584;

是应该创建一个(staff_id,customer_id)索引还是应该颠倒一下顺序?可以跑一些查询来确定在这个表中值的分布情况,并确定哪个列的选择性更高。先用下面的查询预测一下,看看各个WHERE条件的分支对应的数据基数有多大:

*************************** 1. row ***************************SUM(staff_id=2): 7990
SUM(customer_id =584): 30

根据前面的经验法则,应该将索引列customer_id放到前面,因为对应条件值的customer_id数量更小。我们再来看看对于这个customer_id的条件值,对应的staff_id列的选择性如何:

mysql> SELECT SUM(staff_id=2) FROM payment WHERE customer_id=584\G
*************************** 1. row ***************************
SUM(staff_id=2): 17

这样做有一个地方需要注意,查询的结果非常依赖于选定的值。如果按照上述办法优化,可能对其他一些条件值的查询不公平,服务器的整体性能可能变得更糟,或者其他某些查询的运行变得不如预期。如果是诸如pt-query-digest这样的工具的报告中提取"最差"查询,那么再按上述办法选定的索引顺序往往是非常高效的。如果没有类似的具体查询来运行,那么最好还是按照经验法则来做,因为经验法则考虑的是全局基数和选择性,而不是某个具体查询:

mysql> SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,-> COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,-> COUNT(*) FROM payment\G
*************************** 1. row ***************************staff_id_selectivity: 0.0001
customer_id_selectivity: 0.0373COUNT(*): 16044

customer_id的选择性更高,所以答案是将其作为索引列的第一列:

mysql> ALTER TABLE payment ADD KEY(customer_id,staff_id);

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

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

相关文章

WLAN简介

一、WLAN 定义概念 WLAN 即无线局域网&#xff08;Wireless Local Area Network&#xff09;&#xff0c;利用无线通信技术在局部范围内建立的网络。 无需布线&#xff0c;通过无线信号实现设备之间的通信和数据传输。通常由无线接入点&#xff08;Access Point&#xff0c;A…

lda模型:官方处理方式和自己处理数据对比

自己处理数据&#xff0c;然后分批训练&#xff0c;第一步先对比自己处理的方式和官方是否一致。 官方的代码 import gensim from gensim import corpora from gensim.models import LdaModel# 示例数据 documents ["Human machine interface for lab abc computer appl…

YOLO算法输出图像含义以及理解

背景 近日使用YOLO算法进行目标检测任务的时候&#xff0c;对于输出的几张图片产生了疑惑&#xff0c;故在此复习与巩固。 图片说明 confusion_matrix&#xff08;混淆矩阵&#xff09;&#xff1a; 混淆矩阵是一种用来衡量分类模型性能的表格。横坐标为实际真值&#xff0c…

如何使用navigator对象,手写一个正则表达式验证邮箱

1:如何使用 navigator 对象 navigator 对象是 JavaScript 中的一个内置对象,用于获取浏览器和操作系统的信息。以下是一些常用的 navigator 属性和方法: navigator.userAgent: 返回用户代理字符串,可以用于检测浏览器类型和版本。 navigator.platform: 返回操作系统平台。 n…

CANDela studio使用小tips

打开软件的时候注意先选择英文&#xff0c;因为双击CDD/CDDT文件默认打开的是德文&#xff0c;所以最正确的打开方式是先打开CANDela studio&#xff0c;再导入CDD&#xff0c;不仅可以避免用德文打开&#xff0c;还能避免vector软件的bug。 不同的版本有不同的权限。 admin有…

TOPSIS综合评价

TOPSIS法&#xff08;Technique for Order Preference by Similarity to an Ideal Solution&#xff09;是一种常用的综合评价方法&#xff0c;该方法根据有限个评价对象与理想化目标的接近程度进行排序&#xff0c;是在现有的对象中进行相对优劣的评价。 TOPSIS法的原理是通过…

Java-文件操作

一、创建文件 1.创建文件夹 创建文件夹时&#xff0c;注意两个条件&#xff0c;该路径对应的是否为目录&#xff08;dir&#xff09;&#xff0c;该文件夹是否存在。 File Apathnew File("./文件夹A"); //当前路径文件夹的存储路径if(!Apath.exists() &&am…

AI推介-多模态视觉语言模型VLMs论文速览(arXiv方向):2024.05.01-2024.05.10

文章目录~ 1.Pseudo-Prompt Generating in Pre-trained Vision-Language Models for Multi-Label Medical Image Classification2.VLSM-Adapter: Finetuning Vision-Language Segmentation Efficiently with Lightweight Blocks3.Memory-Space Visual Prompting for Efficient …

WeightedRandomSamplerDDP, 加权的DDP采样器

先来看一下WeighedRandomSampler&#xff1a; [docs]class WeightedRandomSampler(Sampler[int]):r"""Samples elements from [0,..,len(weights)-1] with given probabilities (weights).Args:weights (sequence) : a sequence of weights, not necessary s…

JAVA基础----线程池

①什么是线程池&#xff1f; 线程池是对所有线程进行统一的管理和控制&#xff0c;从而提高系统的运行效率。当我们要使用线程的时候可以直接从线程池中拿&#xff0c;用完也不用自己去销毁&#xff0c;省去创建和销毁的时间&#xff0c;提升系统的响应时间。 ②线程池的七大核…

单链表的相关题目

1.删除链表中给定值val的所有结点 public void removeall(int key) {//由于是删除链表中所有和key值相同的结点,所以可以设置两个ListNode类型的数据,一个在前面,一个在后面.//直到前面的走到链表的最后,这样完成了遍历.//先判断一下这个链表是否为空if(headnull){System.out.…

【ArcGIS For JS】前端geojson渲染行政区划图层并加标签

原理 通过DataV工具 生成行政区的geojson&#xff08;得到各区的面元素数据&#xff09;, 随后使用手动绘制featureLayer与Label&#xff0c;并加载到地图。 //vue3加载geojson数据public/geojson/pt.json,在MapView渲染上加载geojson数据 type是"MultiPolygon"fetc…

Vue 3中的v-for指令使用详解

Vue 3中的v-for指令使用详解 一、前言1. 基本语法2. 循环渲染对象3. 在组件中使用v-for4.普通案例5. 其他用法 二、结语 一、前言 在Vue 3中&#xff0c;v-for指令是一个非常强大且常用的指令&#xff0c;它用于在模板中循环渲染数组或对象的内容。本文将为您详细介绍Vue 3中v…

Android项目实战 —— 手把手教你实现一款本地音乐播放器Dora Music

今天带大家实现一款基于Dora SDK的Android本地音乐播放器app&#xff0c;本项目也作为Dora SDK的实践项目或使用教程。使用到开源库有[https://github.com/dora4/dora] 、[https://github.com/dora4/dcache-android] 等。先声明一点&#xff0c;本项目主要作为框架的使用教程&a…

Unity【入门】环境搭建、界面基础、工作原理

Unity环境搭建、界面基础、工作原理 Unity环境搭建 文章目录 Unity环境搭建1、Unity引擎概念1、什么是游戏引擎2、游戏引擎对于我们的意义3、如何学习游戏引擎 2、软件下载和安装3、新工程和工程文件夹 Unity界面基础1、Scene场景和Hierarchy层级窗口1、窗口布局2、Hierarchy层…

跨平台游戏引擎 Axmol-2.1.3 发布

我们非常荣幸&#xff0c;axmol 能在发布此版本之前被 awsome-cpp 收录&#xff01; The 2.1.3 release is a minor LTS release for bugfixes and improvements, we also have new home page: https://axmol.dev , thanks to all contributers of axmol, especially iAndyHD…

多分支拓扑阻抗匹配

最近测试信号质量&#xff0c;发现在有过冲、振铃等问题的时候大部分硬件工程师喜欢直接调大匹配电阻或者减小驱动电流&#xff0c;虽然这种操作是有效果的&#xff0c;但是我认为应该还可以更严谨的计算下&#xff0c;而不是选几个电阻多次尝试&#xff0c;显得不是很专业。 …

一文了解Redis及场景应用

Redis是一个高性能的、开源的、基于键值对&#xff08;Key-Value&#xff09;的数据结构存储系统&#xff0c;它支持网络、内存存储以及可选的持久化特性。 以下是关于Redis的一些详细说明&#xff1a; 核心特性 数据结构丰富&#xff1a; Strings&#xff1a;最基本的数据类型…

call函数实现

call 函数的实现步骤&#xff1a; 判断调用对象是否为函数&#xff0c;即使我们是定义在函数的原型上的&#xff0c;但是可能出现使用 call 等方式调用的情况。 判断传入上下文对象是否存在&#xff0c;如果不存在&#xff0c;则设置为 window 。 处理传入的参数&#xff0c;…

推送镜像到私有harbor仓库

本地已制作镜像&#xff1a;tomcat-8.5.100-centos7.9:1.0。 本地已经搭建私有仓库&#xff1a;harbor.igmwx.com。 现在需要把镜像 tomcat-8.5.100-centos7.9:1.0 推送到harbor。 &#xff08;1&#xff09;查看本地镜像&#xff1a;sudo docker images zhangzkzhangzk:~/d…