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

创建高性能的索引

哈希索引

哈希索引(hash index)基于哈希表实现,只有精确匹配索引所有的列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code).哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时哈希表中保存指向每个数据行的指针。在MySQL中,只有Memory引擎显式支持哈希索引。这也是Memory引擎表的默认索引类型,Memory引擎同时也支持B-Tree索引。值得一提的是,Memory引擎是支持非唯一哈希索引的,这在数据库世界里面是比较与众不同的。如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中.下面来看一个例子

mysql> CREATE TABLE testhash(-> fname VARCHAR(50) NOT NULL,-> lname VARCHAR(50) NOT NULL,-> KEY USING HASH(fname)-> ) ENGINE=MEMORY;

表种包含如下数据:

mysql> SELECT * FROM testhash;
+-------+-----------+
| fname | lname     |
+-------+-----------+
| Arjen | Lentz     |
| Baron | Schwartz  |
| Peter | Zaitsev   |
| Vadim | Tkachenko |
+-------+-----------+

假设索引使用假想的哈希函数f(),它返回下面的值(都是示例数据,非真实数据):

f('Arjen')=2323
f('Baron')=7437
f('Peter')=8784
f('Vadim')=2458

则哈希索引的数据结构如下:

(Slot)(Value)
2323          指向第1行的指针
2458          指向第4行的指针
7437          指向第2行的指针
8784          指向第3行的指针

注意每隔槽的编号是顺序的,但是数据行不是。先在来看如下查询

mysql> SELECT lname FROM testhash WHERE fname ='Peter';

MySQL先计算’Peter’的哈希值,并使用该值寻找对应的记录指针。因为f(‘Peter’)=8784,所以MySQL在索引中查找8784,可以找到指向第3行的指针,最后异步是比较第三行的值是否为’Peter’,以确保就是要查找的行。因为索引自身只需要存储对应的哈希值,所以索引的结构十分紧凑,这也让哈希索引查找的速度非常快。然而,哈希索引也有它的限制:

  • 1.哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中的行的速度很快,所以大部分情况下这一点对性能的影响并不明显
  • 2.哈希索引数据并不是按照索引值顺序存储的,所以也就无法用于排序
  • 3.哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值的。例如,在数据列(A,B)上建立哈希索引,如果查询只有数据列A,则无法使用该索引
  • 4.哈希索引只支持等值比较查询,包括=、IN()、<=>(注意<>和<=>是不同的操作)。也不支持任何范围查询,例如WHERE price >100
  • 5.访问哈希索引的数据非常快,除非有很多哈希冲突(不同的索引列值却有相同的哈希值)。当出现哈希冲突的时候,存储引擎必须遍历链表中所有的行指针,主键进行比较,直到找出所有符合条件的行
  • 6.如果哈希冲突很多的化,一些索引维护操作的代价也会很高。例如,如果在某个选择性很低(哈希冲突很多)的列上建立哈希索引,那么当从表中删除一行时,存储引擎需要遍历对哈希值的链表中的每一行,找到并删除对应行的引用,冲突越多,代价越大。

因为这些限制,哈希索引只适用于某些特定的场合。而一旦适合哈希索引,则它带来的的性能提升将非常显著。举个例子,在数据仓库应用中有一种经典的"星型"schema。需要关联很多表,哈希索引就非常适合查找表的需求。除了Memory引擎外,NDB集群引擎也支持唯一哈希索引,且在NDB集群引擎中作用非常特殊。
InnoDB引擎有一个特殊的功能叫作"自适应哈希索引(Adaptive Hash Index)"。当InnoDB注意到某些索引值被使用得非常频繁时,它会在内存中基于B-Tree之上再创建一个哈希索引,这样就让B-Tree索引也具有哈希索引的一些优点,比如快速的哈希查找。这是一个完全自动的、内部的行为,用户无法控制或者配置,不过有必要,完全可以关闭该功能。

创建自定义哈希索引

如果存储引擎不支持哈希索引,则可以模拟像InnoDB一样创建哈希索引,这可以享受一些哈希索引的便利,例如只需要很小的索引就可以为超长的键创建索引。思路很简单:在B-Tree基础上创建一个伪哈希索引。这和真正的哈希索引不是一回事,因为还是适用B-Tree进行查找,但是它适用哈希值而不是键本身进行索引查找。你需要做的事就是在查询的WHERE子句中手动指定适用哈希函数。下面是一个示例,例如需要存储大量的URL,并需要根据URL进行搜索查找。如果适用B-Tree来存储URL,存储的内容就会很大,因为URL本身都很长。正常情况下会有如下查询:

mysql> SELECT id FROM url WHERE url = "http://www.mysql.com";

若删除原来URL列上的索引,而新增一个被索引的url_crc列,适用CRC32做哈希,就可以适用下面的方式查询:

mysql>SELECT  id FROM url WHERE url="http://www.mysql.com" AND url_crc=CRC32("http://www.mysql.com");

这样做的性能会非常高,因为MySQL优化器会适用这个选择性很高而提及很小的基于url_crc列的索引来完成查找(在上面的案例中,索引值伪1560514994)即使有多个记录相同的索引值,查找仍然很快,只需要根据哈希值做快速的整数比较就能找到索引条目,然后一一比较返回对应的行。另外一种方式就是对完整的URL字符串做索引,那样会非常慢。

mysql> SELECT CRC32("http://www.mysql.com");
+-------------------------------+
| CRC32("http://www.mysql.com") |
+-------------------------------+
|                    1560514994 |
+-------------------------------+
1 row in set (0.10 sec)

这样实现的缺陷事需要维护哈希值。可以手动维护,也可以适用触发器实现。下面的案例演示了触发器如何在插入和更新时维护url_crc列,首先创建如下表:

CREATE TABLE pseudohash (
id INT UNSIGNED NOT NULL auto_increment,
url VARCHAR ( 255 ) NOT NULL,
url_crc INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY ( id ));

然后创建触发器。先临时修改一下语句分隔符,这样就可以在触发器定义中适用分毫:

DELIMITER //
CREATE TRIGGER pseudohash_crc_ins BEFORE INSERT ON pseudohash FOR EACH ROW BEGIN SET NEW.url_crc=crc32(NEW.url);
END;
//CREATE TRIGGER pseudohash_crc_upd BEFORE UPDATE ON pseudohash FOR EACH ROW BEGIN SET NEW.url_crc=crc32(NEW.url);
END;
//DELIMITER;

剩下工作就是验证一下触发器如何维护哈希索引:

mysql>INSERT INTO pseudohash (url) VALUES ('http://www.mysql.com');
mysql> SELECT * FROM pseudohash;
+----+----------------------+------------+
| id | url                  | url_crc    |
+----+----------------------+------------+
|  1 | http://www.mysql.com | 1560514994 |
+----+----------------------+------------+
1 row in set (0.08 sec)
mysql> UPDATE pseudohash SET url = 'http://www.mysql.com/' WHERE id = 1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> SELECT * FROM pseudohash;
+----+-----------------------+------------+
| id | url                   | url_crc    |
+----+-----------------------+------------+
|  1 | http://www.mysql.com/ | 1558250469 |
+----+-----------------------+------------+
1 row in set (0.07 sec)

SHA1()和MD5()

如果采用这种方式,记住不要适用SHA1()和MD5(0作为哈希函数。因为这两个函数计算出来的哈希值是非常长的字符串,会浪费大量空间,比较时也会更慢。SHA1()和MD5()是强加密函数,设计目标是最大限度消除冲突,但这里并需要这样高的要求。简单哈希函数的冲突在一个可以接受的范围,同时又能够提供好的性能。如果数据表非常大,CRC32()会出现大量的哈希冲突,则可以考虑自己实现一个简单的64位哈希函数。这个自定义函数要返回整数,而不是字符串。一个简单的办法可以适用MD5()函数返回值的一部分来作为自定义哈希函数。这可能比自己写一个哈希算法的性能要差,不过这样实现最简单:

mysql> SELECT CONV(RIGHT(MD5('http://www.mysql.com/'), 16), 16, 10) AS HASH64;
+---------------------+
| HASH64              |
+---------------------+
| 9761173720318281581 |
+---------------------+

处理哈希冲突,当适用哈希索引进行查询的时候,必须在WHERE子句中包含常量值:

mysql> SELECT id FROM url WHERE url_crc=CRC32('http://mysql.com') AND url='http://www.mysql.com';

一旦出现哈希冲突,另一个字符串的哈希值也恰是1560514994,则下面的查询时无法正确工作的。

mysql> SELECT id FROM url WHERE url_crc=CRC32('http://www.mysql.com');

因为所谓的"生日悖论",出现哈希冲突的概率的增长速度可能比想象的要快得多。CRC32()返回的是32位的整数,当索引有93 000条时出现的冲突的概率是1%。例如将/usr/share/dict/words中的词导入数据表并进行CRC32()计算,最后会有98 569行,这就已经出现一次哈希冲突了,冲突让下面的插叙年返回了多条记录

mysql>SELECT word,crc FROM words WHERE crc=CRC32('gnu');

正确的刑法应该如下:

mysql>SELECT word, crc FROM words WHERE crc=CRC32('gnu') AND word = 'gnu';

要避免冲突问题,必须在WHERE条件中带入哈希值和对应列值。如果不是想查询具体值,例如只是统计记录数(不精确的),则可以不带如列值,直接适用CRC32()的哈希值查询即可。还可以适用如FNV64()函数作为哈希函数,这是移植自Percona Server的函数,可以以插件的方式在任何MySQL版本中适用,哈希值64位,速度快,且冲突比CRC32()要少很多

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

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

相关文章

波兰表达式c语言递归

波兰表达式&#xff08;Polish Notation&#xff09;&#xff0c;又称前缀表达式&#xff0c;是一种没有括号的算术表达式&#xff0c;其中运算符位于操作数之前。与常见的中缀表达式&#xff08;如常见的数学表达式&#xff09;不同&#xff0c;波兰表达式避免了对括号的需求&…

isscc2024 short course4 In-memory Computing Architectures

新兴的ML加速器方法&#xff1a;内存计算架构 1. 概述 内存计算&#xff08;In-memory Computing&#xff09;架构是一种新兴的机器学习加速器方法&#xff0c;通过将计算能力集成到存储器中&#xff0c;以减少数据移动的延迟和能耗&#xff0c;从而提高计算效率和性能。这种方…

linux mv操作和cp操作

mv 和 cp 是 Linux 系统中用于移动和复制文件或文件夹的两个常用命令&#xff0c;它们之间的主要区别在于&#xff1a; mv&#xff08;move&#xff09;&#xff1a;mv 命令用于移动文件或文件夹&#xff0c;将它们从一个位置移动到另一个位置。移动后&#xff0c;原始文件或文…

服务器软件架构演进

服务器软件架构演进 背景介绍阶段一&#xff1a;单机部署阶段二&#xff1a;应用与数据分离部署阶段三&#xff1a;启用缓存优化阶段四&#xff1a;启用应用服务器集群阶段五&#xff1a;数据库读写分离阶段六&#xff1a;启用反向代理及CDN加速阶段七&#xff1a;启用分布式文…

ComfyUI简单介绍

&#x1f353;什么是ComfyUI ComfyUI是一个为Stable Diffusion专门设计的基于节点的图形用户界面&#xff0c;可以通过各种不同的节点快速搭建自己的绘图工作流程。 软件打开之后是长这个样子&#xff1a; 同时软件本身是github上的一个开源项目&#xff0c;开源地址为&#…

【WEB前端2024】开源智体世界:乔布斯3D纪念馆-第28课-avatar玩家3D形象

【WEB前端2024】开源智体世界&#xff1a;乔布斯3D纪念馆-第28课-avatar玩家3D形象 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界…

零售EDI:Target DVS EDI项目案例

Target塔吉特是美国一家巨型折扣零售百货集团&#xff0c;与全球供应商建立长远深入的合作关系&#xff0c;目前国内越来越多的零售产品供应商计划入驻Target。完成入驻资格审查之后&#xff0c;Target会向供应商提出EDI对接邀请&#xff0c;企业需要根据指示完成供应商EDI信息…

windows 控制面板卸载程序在注册表中位置

计算机\HKEY_LOCAL_MACHINE或者HKEY_CURRENT_USER\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\荐片高清影音 HKEY_CURRENT_USER 控制面板注册表只有当前用户可见 HKEY_LOCAL_MACHINE 控制面板注册表所有用户可见

【STM32踩坑】HAL固件库版本过高导致烧录后无法运行问题

问题引入 目前STM32CUBEMX已经更新到了6.11版本&#xff0c;对应的固件库也一直在更新&#xff1b; 以STM32F1库为例&#xff0c;目前最新的库对应版本为1.8.5 但是我们会发现&#xff0c;如果直接使用1.8.5版本的固件库生成HAL源码后&#xff0c;烧录是可以烧录&#xff0c;但…

Python每秒1000次压测

Molotov是一个用Python编写的轻量级HTTP负载测试工具,旨在帮助开发者进行简单的性能测试和压力测试。它通过模拟大量并发用户访问来测试Web服务的响应时间、吞吐量以及稳定性。Molotov特别强调易用性和可扩展性,允许用户自定义场景和断言来更好地适应不同应用的测试需求。 安…

leetcode栈和队列的相关题、有效的括号、用队列实现栈、用栈实现队列、设计循环队列等介绍

文章目录 前言一、有效的括号二、用队列实现栈三、 用栈实现队列四、设计循环队列总结 前言 leetcode栈和队列的相关题、有效的括号、用队列实现栈、用栈实现队列、设计循环队列等介绍 一、有效的括号 leetcode有效的括号 // 动态增长的栈 typedef char STDataType; typedef…

香港优才计划需要什么条件?一文给你说清2024优才政策、申请利弊及获批攻略

香港优才计划申请&#xff0c;竞争正逐渐加剧&#xff0c;在正式递交申请前&#xff0c;客观评估自身申请条件&#xff0c;找准个人履历中与香港人才引进的契合点&#xff0c;并在申请材料中详细表明&#xff0c;更有助于获批。 在申请之前&#xff0c;我们必须明白一个事实&a…

Hack The Box-BoardLight

总体思路 子域名收集->默认密码->信息泄露->CVE-2022-37706 信息收集&端口利用 nmap -sSVC boardlight.htb发现22和80端口开放&#xff0c;先看80端口网站信息 四处查看后&#xff0c;发现没有有效信息&#xff0c;对其进行目录扫描和子域名扫描 dirsearch -u…

總結力學_2

個人近況 最近搞了畢業論文,讓大家久等了... 梳理路徑 "普通物理学习的是基本的想法。这些想法最好能在学习过程中简单、直接地呈现出来。绝大部分的前沿知识无法满足这个要求。所谓前沿常常指的是新发现的事实,并未超出那些基本的想法,正所谓“太阳底下无新事”。真…

【吊打面试官系列】Java高并发篇 - 线程的调度策略?

大家好&#xff0c;我是锋哥。今天分享关于 【线程的调度策略?】面试题&#xff0c;希望对大家有帮助&#xff1b; 线程的调度策略? 线程调度器选择优先级最高的线程运行&#xff0c;但是&#xff0c;如果发生以下情况&#xff0c;就会终止线程的运行&#xff1a; 1、线程体…

ROS for LabVIEW:实现LabVIEW与ROS的无缝集成

ROS for LabVIEW是由Tufts大学开发的一套VI集合&#xff0c;旨在实现LabVIEW与ROS&#xff08;Robot Operating System&#xff09;的无缝集成。ROS是一个灵活的机器人软件框架&#xff0c;而LabVIEW则是一种强大的图形化编程工具。这个工具包的推出使得LabVIEW用户能够直接与R…

ACM实训冲刺第二十天

SUM Problem&#xff08;数学计算与序列求和&#xff09; 这段代码实现的是计算一个正整数n与其之前的所有正整数之和的问题&#xff0c;它属于数学计算与序列求和的题型。具体算法根据输入整数n的奇偶性采用了两种形式的等差数列求和公式&#xff1a; 如果n是偶数&#xff0c;…

时隔1年,我终于弄懂了Java 中的 AOP操作

1. AOP概述 2. AOP快速入门 依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>${spring-boot.version}</version></dependency> 示例:记…

如何使用 Re-Ranking 改进大模型 RAG 检索

基于大型语言模型&#xff08;LLMs&#xff09;的聊天机器人可以通过检索增强生成&#xff08;RAG&#xff09;提供外部知识来改进。 这种外部知识可以减少错误答案&#xff08;幻觉&#xff09;&#xff0c;并且使模型能够访问其训练数据中未包含的信息。 通过RAG&#xff0…

ciscn

ciscn Crypto部分复现 古典密码 先是埃特巴什密码&#xff08;这个需要进行多次测试&#xff09;&#xff0c;然后base64&#xff0c;再栅栏即可 答案&#xff1a;flag{b2bb0873-8cae-4977-a6de-0e298f0744c3} _hash 题目&#xff1a; #!/usr/bin/python2 # Python 2.7 (6…