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

创建高性能的索引

空间数据索引(R-Tree)

MyISAM表支持空间索引,可以用作地理数据存储。和B-Tree索引不同,这类索引无须前缀查询。空间索引会从所有维度来索引数据。查询时,可以有效地使用任意维度来组合查询。必须使用MySQL的GIS相关函数如MBRCONTAINS()等来维护数据。MySQL的GIS支持并不完善,所以大部分人都不会使用这个特性。开源关系数据库系统中对GIS的解决方案做得比较好的是PostgreSQL的PostGIS.

全文索引

全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值。全文搜索和其他几类索引的匹配方式完全不一样。它有许多需要注意的细节,如停用词、词干和复数、布尔搜索等。全文索引更类似于搜索引擎作得事情,而不是简单的WHERE条件匹配。
在相同的列上同时创建全文索引和基于值得B-Tree索引不会有冲突,全文索引适用于MATCH AGAINST操作,而不是普通得WHERE条件操作

索引的优点

索引可以让服务器快速地定位到表的指定位置。但是这并不是索引的唯一作用,到目前为止可以看到,根据创建索引的数据结构不同,索引也有一些其他的附加作用。最常见的B-Tree索引,按照顺序存储数据,所有MySQL可以用来做ORDER BY 和GROUP BY操作。因为数据是有序的,所以B-Tree也就会将相关的列值存储在一起。最后,因为索引中存储了实际的列值,所以某些查询只使用索引就能够完成全部查询。据此特性,总结下来索引有如下三个优点:

  • 1.索引大大减少了服务器需要扫描的数据量
  • 2.索引可以帮助服务器避免排序和临时表
  • 3.索引可以将随机IO变为顺序IO

索引这个主题完全值得单独写一本书,如果想深入理解这部分内容,强烈建议阅读由Tapio Lahdenmaki和Mike Leach编写的Relational Database Index Design and the Optimizers(Wiley出版社)一书,该书详细介绍了如何计算索引的成本和作用、如何评估查询速度、如何分析索引维护的代价和其带来的好处等.Lahdenmaki和Leach在书中介绍了如何评价一个索引是否适合某个查询的"三星系统"(three-star system):索引将相关的记录放到一起则获得一星;如果索引中的数据顺序和查找的排列顺序一致则获得二星;如果索引中的列包含了查询中需要的全部列则获得三星

索引是最好的解决方案吗?

索引并不总是最好的工具。总的来说,只有当索引帮助存储引擎快速查找到记录带来的好处大于其带来的额外工作时,索引才是有效地。对于非常小的表,大部分情况下简单的全表扫描更高效。对于中到大型的表,索引就非常有效。但对于大型的表,建立和使用索引的代价将随之增长。这种情况下,则需要一种技术可以直接区分出查询需要的一组数据,而不是一条记录一条记录地匹配。例如可以使用分区技术。如果表的数量特别多,可以建立一个元数据信息表,用来查询需要用到的某些特性。例如执行那些需要聚合多个应用分布在多个表的数据的查询,则需要记录"哪个用户的信息存储在哪个表中"的元数据,这样在查询时就可以直接忽略那些不包含指定用户信息的表。对于大型系统,这是一个常用的技巧,事实上,Infobright就是使用类似的实现。对于TB级别的数据,定位单条记录的意义不大,所以经常会使用块级别元数据技术来替代索引

高性能的索引策略

正确地创建和使用索引是实现高性能查询的基础。前面已经介绍了各种类型的索引及其对应的优缺点。现在一起来看看如何真正地发挥这些索引的优势。
高效地选择和使用索引有很多种方式,其中有些是针对特殊案例的优化方法,有些则是针对特定行为的优化。使用哪个索引,以及如何评估选择不同索引的性能影响的技巧,则需要持续不断地学习。

独立的列

我们通常会看到一些查询不当地使用索引,或者使得MySQL无法使用已有的索引。如果查询中的列不是独立的,则MySQL就不会使用索引。"独立的列"是指索引不能是表达式的一部分,也不能是函数的参数。例如,下面这个查询无法使用actor_id列的索引:

mysql> SELECT actor_id FROM actor WHERE actor_id + 1 =5;

凭肉眼很容易看出WHERE中的表达式其实等价于actor_id=4,但是MySQL无法自动解析这个方程式。这完全是用户行为。我们应该养成简化WHERE条件的习惯,始终将索引列单独放在比较符号的一侧。下面是另一个常见的错误:

mysql> SELECT .... WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col) <= 10;

前缀索引和索引选择性

有时候需要索引很长的字符列,这会让索引变得大且慢。一个策略是前面提到过的模拟哈希索引。但有时候这样做还不够,还可以做些什么呢?
通常可以索引开始的部分字符,这样可以大大节约索引空间,从而提高索引效率。但这样也会降低索引的选择姓。索引的选择性是指,不重复的所引致(也成为技术,cardinality)和数据表的记录总数(#T)的比值。范围从1/#T到1之间。索引的选择性越高则查询效率越高,因为选择性高的索引可以让MySQL在查找时过滤掉更多的行。唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

一般情况下某个列前缀的选择性也是足够高的,足以满足查询性能。对于BLOB、TEXT或者很长的VARCHAR类型的列,必须使用前缀索引,因为MySQL不允许索引这些列的完整长度。诀窍在于要选择足够长的前缀以保证较高的选择性,同时又不能太长(以便节约空间)。前缀应该足够长,以使得前缀索引的选择性接近于索引整个列。换句话说,前缀的"技术"应该接近于完整列的"基数"。为了决定前缀的合适长度,需要找到最常见的值得列表,然后和最常见得前缀列表进行比较。(MySQL Sakila官方链接http://downloads.mysql.com/docs/sakila-db.zip)大家可以下载下来导入进去。这里从表city中生成一个示例表,这样就有足够得数据进行演示:

use sakila;
CREATE TABLE city_demo(city VARCHAR(50) NOT NULL);INSERT INTO city_demo(city) SELECT city FROM city;INSERT INTO city_demo(city) SELECT city FROM city_demo;# 执行五次UPDATE city_demo SET city = (SELECT city FROM city ORDER BY RAND() LIMIT 1);

现在我们有了示例数据集。数据分布当然不是真实得分布;因为我们使用了RAND().所以你的结果会与此不同,但对这个例子说这并不重要。首先,我们找到最常见的城市列表:

mysql> SELECT COUNT(*) AS cnt,city FROM city_demo GROUP BY city ORDER BY cnt DESC LIMIT 10;
+-----+-------------+
| cnt | city        |
+-----+-------------+
|  64 | London      |
|  50 | Bagé        |
|  49 | Brockton    |
|  48 | Soshanguve  |
|  47 | Bucuresti   |
|  47 | El Alto     |
|  47 | Balašiha    |
|  46 | Osmaniye    |
|  46 | Arecibo     |
|  45 | Santo André |
+-----+-------------+
10 rows in set (0.09 sec)

注意到,上面每隔值都出现了45~64次。现在查找结果最频繁出现的城市前缀,先从前3个前缀字母开始:


mysql> SELECT COUNT(*) AS cnt, LEFT(city, 3) AS pref FROM city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 10;
+-----+------+
| cnt | pref |
+-----+------+
| 456 | San  |
| 175 | Cha  |
| 174 | Tan  |
| 172 | Sou  |
| 165 | Sal  |
| 144 | al-  |
| 128 | Man  |
| 127 | Hal  |
| 124 | Bal  |
| 122 | Shi  |
+-----+------+
10 rows in set (0.08 sec)

每个前缀都比原来的城市出现的次数更多,因此唯一前缀比唯一城市要少得多。然后我们增加前缀长度,直到这个前缀的选择性接近完整列的选择性。经过实验后发现前缀为7时比较合适:

mysql> SELECT COUNT(*) AS cnt, LEFT(city, 7) AS pref FROM city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 10;
+-----+---------+
| cnt | pref    |
+-----+---------+
|  64 | London  |
|  62 | San Fel |
|  60 | Santiag |
|  58 | Valle d |
|  50 | Bagé    |
|  49 | Brockto |
|  48 | Soshang |
|  47 | El Alto |
|  47 | Bucures |
|  47 | Balaših |
+-----+---------+
10 rows in set (0.08 sec)

计算合适的前缀长度的另外一个办法就是计算完整列的选择性,并使前缀的选择性接近于完整列的选择性。下面显式如何计算完整列的选择性:

mysql> SELECT COUNT(DISTINCT city)/COUNT(*) FROM city_demo;
+-------------------------------+
| COUNT(DISTINCT city)/COUNT(*) |
+-------------------------------+
| 0.0312                        |
+-------------------------------+
1 row in set (0.08 sec)

通常来说(尽管也有例外情况)。这个例子中如何前缀的选择性能够接近0.031,基本上就可以可用了。可以在一个查询中针对不同前缀长度进行计算,这对于大表非常有用,下面给出了如何在同一个查询中计算不同前缀长度的选择性:

mysql>  SELECT
COUNT(DISTINCT LEFT(city,3))/COUNT(*)  AS sel3,COUNT(DISTINCT LEFT(city,4))/COUNT(*)  AS sel4,
COUNT(DISTINCT LEFT(city,5))/COUNT(*)  AS sel5,COUNT(DISTINCT LEFT(city,6))/COUNT(*)  AS sel6,COUNT(DISTINCT LEFT(city,7))/COUNT(*)  AS sel7
FROM city_demo;
+--------+--------+--------+--------+--------+
| sel3   | sel4   | sel5   | sel6   | sel7   |
+--------+--------+--------+--------+--------+
| 0.0237 | 0.0293 | 0.0305 | 0.0309 | 0.0310 |
+--------+--------+--------+--------+--------+

查询显式当前缀长度达到7的时候,再增加前缀长度,选择性能提升的复度已经很小了,只看平均选择性使不够的,也有例外的情况,需要考虑最坏情况下的选择性。平均选择性会让你认为前缀长度4或者5的索引已经足够了,但如果数据分布很不均匀,可能就会有陷阱。如果观察前缀为4的最常出现城市的次数,可以看到明显不均匀:

mysql> SELECT COUNT(*) AS cnt, LEFT(city,4) AS pref FROM city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 5;
+-----+------+
| cnt | pref |
+-----+------+
| 203 | San  |
| 190 | Sant |
| 141 | Sout |
|  98 | Chan |
|  85 | Toul |
+-----+------+

如果前缀事4个字节,则最常出现的前缀的出现次数比最常出现的城市的出现次数要大很多。即使这些值的选择性比平均选择性要地。如果有比这个随机生成的示例更真实地数据,就更有可能看到这种现象。例如在真实的城市名上建一个长度为4地前缀索引,对于以"San"和"New"开头地城市地选择性就会非常糟糕,因为很多城市都以这两个词开头。

在上面地示例中,已经找到了合适的前缀长度,下面演示如何创建前缀素银:

mysql> ALTER TABLE city_demo ADD KEY(city(7));

前缀索引是一种使索引更小、更快的有效方法,但另一方面也有其缺点:MySQL无法使用前缀索引做ORDER BY 和GROUP BY,也无法使用前缀索引做覆盖扫描。一个常见的场景使针对很长的十六进制唯一ID使用前缀索引。

有时候后缀索引(suffix index)也有用途(例如,找到某个域名的所有电子邮件地址)。MySQL原生不支持反向索引,但是可以把字符串反转后存储,并基于词建立前缀索引

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

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

相关文章

AcWing 2568:树链剖分 ← 线段树+DFS

【题目来源】https://www.acwing.com/problem/content/2570/【题目描述】 给定一棵树&#xff0c;树中包含 n 个节点&#xff08;编号 1∼n&#xff09;&#xff0c;其中第 i 个节点的权值为 ai。 初始时&#xff0c;1 号节点为树的根节点。 现在要对该树进行 m 次操作&#xf…

5.28总结

HTML 三剑客&#xff1a; JS CSS HTML 入门实例 新建一个test.html文件&#xff0c;内容如下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…

央视网视频下载和花屏问题处理

央视网(www.cctv.com)视频下载往往是花屏的&#xff0c;如何处理呢&#xff1f; 如果您是IT技术开发者&#xff0c;那么您可以通过下面步骤自己实现。 用chrome浏览器&#xff0c;F2打开开发者工具&#xff0c;找到当前页面的network 然后找一个接口&#xff1a;https://vdn.a…

【Python-基础】字典合集

遍历所有键 # vis_params{vis_level: -1, line_thickness: 500} for key in vis_params.keys():注&#xff1a; vis_params &#xff1a; 字典数据 未完待续…

Android UI:ViewTree: 监听

文章目录 涉及设计模式 ​​​​​​​​​​​​​​观察者模式+策略模式API源码分析总结涉及设计模式 观察者模式+策略模式 被观察者:ViewTree ViewTree持有一个观察器ViewTreeObserver 系统在ViewRootImpl和View的相关方法中调用ViewTreeObserver上的注册的监听器的方法,…

文生图模型演进:AE、VAE、VQ-VAE、VQ-GAN、DALL-E 等 8 模型

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 合集&#x…

OC IOS 文件解压缩预览

热很。。热很。。。。夏天的城市只有热浪没有情怀。。。 来吧&#xff0c;come on。。。 引用第三方库&#xff1a; pod SSZipArchive 开发实现&#xff1a; 一、控制器实现 头文件控制器定义&#xff1a; // // ZipRarViewController.h // // Created by carbonzhao on 2…

JavaScript与版本控制:编译时光机的双重奏——git仓库

JavaScript与版本控制&#xff1a;编译时光机的双重奏——git仓库 JavaScript&#xff1a;代码的魔法棒版本控制&#xff1a;时光机的钥匙案例一&#xff1a;初始化Git仓库与基本操作初始化仓库添加文件至暂存区提交更改分支管理 案例二&#xff1a;JavaScript项目中的Gitignor…

OTFS系统建模、通信性能分析、信道估计、模糊函数【附MATLAB代码】

文献来源&#xff1a;​微信公众号&#xff1a;EW Frontier OTFS简介 OTFS信道估计 % Clear command window, workspace variables, and close all figures clc; clear all; close all; ​ % Define Eb values in dB EbdB -10:2:10; ​ % Convert Eb values from dB to lin…

【测评】香橙派 AIpro上手初体验

AI毋庸置疑是近年来&#xff0c;热度最高的技术之一&#xff0c;作为一名工程师拥抱新技术的同时不可或缺的需要一块强悍的开发板&#xff0c;香橙派 AIpro除了拥有好看的皮囊之外&#xff0c;还拥有一个有趣且充满魅力的灵魂。作为一位长期活跃在嵌入式开发领域的工程师&#…

OrangePi AIpro (8T)使用体验,性能测试报告

前言 这段时间收到了CSDN和香橙派的邀请&#xff0c;对OrangePi AIpro进行体验测评&#xff0c;在此感谢CSDN对我的信任&#xff0c;也感谢香橙派能做出如此优秀的开发板。 可喜可贺&#xff0c;周三晚上我收到了官方寄出的OrangePi AIpro。出于对国产芯片的好奇&#xff0c…

二分答案思想下的二进制问题

序列合并 题目描述 给定一个长度为 n n n 的非负整数序列 { a n } \{a_n\} {an​}&#xff0c;你可以进行 k k k 次操作&#xff0c;每次操作你选择两个相邻的数&#xff0c;把它们合并成它们的按位或。 形式化地&#xff0c;一次操作中&#xff0c;你选择一个下标 i i …

前端 webSocket配置代理

vue, react. nginx 配置反向代理&#xff0c;解决跨域问题 前端请求 如果配置了 wss 协议&#xff0c; 可以将ws 替换为 wss 这里和我们通常使用的方式不同websocket 需要传入完整的地址&#xff0c;然后才能去做代理 let url ${location.protocol https ? wss : ws}://$…

李廉洋:5.29黄金原油持续震荡,今日美盘行情走势分析及策略。

黄金消息面分析&#xff1a;美联储理事鲍曼周二表示&#xff0c;她支持要么先等等再开始放缓缩减资产负债表&#xff0c;要么采取比本月早些时候宣布的更温和的放慢缩表进程。鲍曼认为商业银行准备金水平仍然充足&#xff0c;这让官员们有更多时间来推进缩表进程。“在准备金接…

unity 多个相机的问题

前段时间写个小功能&#xff0c;发现个问题在scene里面写好了程序&#xff0c;但是导出后显示的和场景里面完全不一样经过查找后发现&#xff0c;原来是我购买的模型下面他自己带了一个相机&#xff0c;在打包出去后&#xff0c;显示的是这个相机的渲染内容。只要把这个相机删除…

你的手机是如何控制你的手表之广播篇

前言 要让手机能够控制手表&#xff0c;第一步当然要让手机能够“看见”手表&#xff0c;人类作为上帝视角&#xff0c;我们是能够通过眼睛直接看见手机和手表的&#xff0c;但要让手机“看见”手表&#xff0c;就需要一端把自己的信息通过电磁波的形式发往空中&#xff0c;另…

Excel中怎样将第一行建立好的规则套用到每一行?

考虑使用条件格式来完成&#xff0c;有两种方式可以尝试&#xff1a; 一、一次性创建条件格式 1.选中需要设置条件格式的区域&#xff0c;如果是不连续的区域&#xff0c;可以按住Ctrl键&#xff0c;然后用鼠标依次选中需要的数据区域 2.点击 开始选项卡&#xff0c;条件格式…

解决Plugin ‘maven-clean-plugin:3.1.0‘ not found的问题

1. 问题描述 当导入别人的Maven项目时&#xff0c;可能会出现Plugin maven-clean-plugin:3.1.0 not found的错误信息。 2. 解决方案 2.1 方案一 检查自己的Maven仓库地址是否正确&#xff0c;一般引入其他人的项目时&#xff0c;Maven仓库的目录以及配置都会是别人的&#xff…

TypeScript 学习笔记(四):装饰器与高级编程技巧

1. 引言 在前几篇学习笔记中,我们已经了解了 TypeScript 的基础知识、高级类型系统以及模块与命名空间的使用。本篇将深入探讨 TypeScript 中的装饰器与一些高级编程技巧,帮助你在实际项目中更好地利用 TypeScript 的强大功能。 2. 装饰器 装饰器(Decorators)是 TypeScr…

Broker的主从架构

为了保证MQ的数据不丢失而且具备一定的高可用性&#xff0c;所以一般都是得将Broker部署成Master-Slave模式的&#xff0c;也就是—个Master Broker对应一个Slave Broker Master需要在接收到消息之后&#xff0c;将数据同步给Slave&#xff0c;这样一旦Master Broker挂了&#…