高性能MySQL实战(二):索引

2023-11-20

我们在上篇 高性能MySQL实战(一):表结构 中已经建立好了表结构,这篇我们则是针对已有的表结构和搜索条件为表创建索引。

1. 根据搜索条件创建索引

我们还是先将表结构的初始化 SQL 拿过来:

CREATE TABLE `service_log` (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
  `service_type` smallint NOT NULL DEFAULT -1 COMMENT '接口类型',
  `service_name` varchar(30) DEFAULT '' COMMENT '接口名称',
  `service_method` tinyint NOT NULL DEFAULT -1 COMMENT '接口方式 1-HTTP 2-TCP',
  `serial_no` int DEFAULT -1 COMMENT '消息序号',
  `service_caller` tinyint DEFAULT -1 COMMENT '调用方',
  `service_receiver` tinyint DEFAULT -1 COMMENT '接收方',
  `status` tinyint DEFAULT 10 COMMENT '状态 10-成功 20-异常',
  `error_message` varchar(200) DEFAULT '' COMMENT '异常信息',
  `message` varchinar(1000) DEFAULT '' COMMENT '报文内容',
  `create_user` varchar(50) DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_user` varchar(50) DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_delete` tinyint NOT NULL DEFAULT 0 COMMENT '刪除标志',
  `ts` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '时间戳',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='接口调用日志';

现有如下搜索条件:

  1. 根据 接口名称 来搜索对应的调用日志
  2. 根据 状态 查询成功或异常的调用日志
  3. 根据 接口名称状态 查询调用日志
  4. 根据 消息序号 来获取一组调用日志
  5. 根据 创建时间 的时间范围查询调用日志
  6. 根据 报文内容 查询调用日志

索引是提升查询性能最有效的手段,它可以快速定位到记录,大大减少需要扫描的数据量,将随机 I/O 变为顺序 I/O,而且 B+ Tree 索引会根据索引值顺序存储,所以也能够应用于 排序和分组

为了在查看这些接口调用日志时有更好的体验,那么我们就需要根据搜索条件来创建索引。

索引的类型尽量小

我们先关注下接口名称的搜索条件,我们可以发现:接口名称和接口类型这两个字段都能查询到相同类型接口的日志数据,只不过它们的类型不同,前者是字符串类型,后者是整型。

这时我们需要注意:选择创建索引的列的类型要尽量小。因为每创建一个索引就相当于创建了“一棵 B 树”,数据类型越小,那么索引占用的存储空间就越少,在一个数据页内就能存放更多的记录,因此磁盘 I/O 带来的性能损耗也就越少

除此之外,在 MySQL 内部整型数据的比较相比于字符串类型的比较更简单,效率也更高。所以,我们会选择为接口类型创建索引而不是为接口名称创建索引。

接口类型 列添加索引的 SQL 如下:

alter table service_log add index index_service_type(`service_type`);

根据条件 4,消息序号列也需要添加索引:

alter table service_log add index index_serial_no(`serial_no`);

冗余和重复索引

同样地,根据搜索条件 2,我们为状态列添加上索引:

alter table service_log add index index_status(`status`);

这时,我们再看看条件 3,需要为接口类型和状态添加 联合索引。不过需要注意的是:该联合索引和已经添加的接口类型索引是重复索引,根据联合索引的 最左匹配原则,第一列为接口类型的联合索引同样能为查询条件只有接口类型的查询服务,所以我们需要将原有为接口类型添加的索引删掉,再创建新的接口类型和状态的联合索引。

-- 删除 index_service_type
alter table service_log drop index index_service_type;

-- 添加联合索引
alter table service_log add index index_service_type_status(`service_type`, `status`);

创建联合索引时有一个重要的经验性法则:将列值重复率最低的放到索引的最前列。如果重复的值过多,那么扫描到的数据行数也就越多,这样就会使得回表的压力很大。

通常情况下,把 WHERE 条件里面的列都独立地创建多个单列索引,在大部分情况下并不能提高MySQL的查询性能。我们应该尽可能的去考虑 索引列的顺序 或者创建一个 全覆盖索引

为重复率低的列创建索引

在我们的实际业务中,接口调用的状态几乎所有都是成功,很少会出现失败的情况,所以这时我们为状态列创建索引并不是很合适。因为如果我们查询所有状态为成功的数据,那么它可能会执行太多次的回表操作,导致查询效率下降,可能还不如执行全表扫描来的快。但是我们再考虑另一种情况,有时我们会根据状态为失败的记录做业务分析或排查问题,失败的数据是比较少的,如果我们通过索引查询就会非常高效,所以该列索引还有必要保留。

只不过我们在这里需要做一个处理:如果状态为成功时,我们为生成的 SQL 语句添加上忽略索引的关键字 ignore index(index_name) ,那么这样我们就能达到在查询成功状态的数据时全表扫描,而在查询失败状态的数据时使用索引了。

select * from service_log ignore index(index_status)
where status = 10;

全值匹配和按值范围匹配的时间列

条件 5 根据创建时间来进行全值匹配和按值范围匹配 非常适合创建索引:

alter table service_log add index index_create_time(`create_time`);

全文索引

FULLTEXT 全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值,更类似于搜索引擎所做的事情。在查询时适用于 MATCH AGAINST 操作,而不是普通的 WHERE 条件。

对于条件 5,我们需要在接口请求的报文中根据关键字,比如说包裹号来查询特定的数据,这就使得我们需要为报文内容列创建全文索引,SQL 如下:

alter table service_log add fulltext fulltext_message(`message`);

-- 执行查询时的语句
select * from service_log where match(message) against('123456');

全文索引在日常使用的并不多,它有许多需要注意的细节,如停用词、词干、复数和布尔搜索等,具体的详情信息可以查看文末的参考文献。

那么,最终初始化表结构的 DDL 语句如下:

CREATE TABLE `service_log` (
  `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
  `service_type` smallint NOT NULL DEFAULT -1 COMMENT '接口类型',
  `service_name` varchar(30) DEFAULT '' COMMENT '接口名称',
  `service_method` tinyint NOT NULL DEFAULT -1 COMMENT '接口方式 1-HTTP 2-TCP',
  `serial_no` int DEFAULT -1 COMMENT '消息序号',
  `service_caller` tinyint DEFAULT -1 COMMENT '调用方',
  `service_receiver` tinyint DEFAULT -1 COMMENT '接收方',
  `status` tinyint DEFAULT 10 COMMENT '状态 10-成功 20-异常',
  `error_message` varchar(200) DEFAULT '' COMMENT '异常信息',
  `message` varchar(1000) DEFAULT '' COMMENT '报文内容',
  `create_user` varchar(50) DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_user` varchar(50) DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_delete` tinyint NOT NULL DEFAULT 0 COMMENT '刪除标志',
  `ts` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '时间戳',
  PRIMARY KEY (`id`),
  index index_serial_no(`serial_no`),
  index index_status(`status`),
  index index_create_time(`create_time`),
  index index_service_type_status(`service_type`, `status`),
  fulltext fulltext_message(`message`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='接口调用日志';

前缀索引

一般情况下,对于 VARCHAR、BLOB 和 TEXT 等相关类型的列创建索引时,为了提升索引的性能和节省索引空间,会只对字段的前一部分字符进行索引,不过这样做的缺点是使得索引的选择性降低。

索引的选择性是指不重复的索引值和记录总数的比值,可以理解为重复率越低选择性越高,唯一索引的选择性为 1。

在我们的数据库表示例中,并没有字段适合建立前缀索引。其中报文内容列也并不适合创建前缀索引,因为这些报文的前缀都很相似,而且我们在执行查询时并不会带上前缀,而是只使用关键词信息查询。

但是,前缀索引比较重要,所以我们在这里也对创建前缀索引的方法介绍一下。

MySQL 并不支持对这些长字符类型列的完整内容进行索引,我们选择前缀长度的关键点在于:既要保证选择足够长的前缀使得选择性较高,同时又不能太长防止占用太多的空间。

可以根据如下方法来确定前缀的长度:

首先,查看要添加索引的列出现最频繁的一些值:

select count(0) as c, specific_column
from specific_table
group by specific_column
order by c desc
limit 10;

之后先从 3 个前缀字母开始匹配尝试:

select count(0) as c, left(specific_column, 3) as pref
from specific_table
group by pref
order by c desc
limit 10;

慢慢地增加前缀长度,直到这个前缀的选择性接近我们首次查询的完整列的选择性即可。

或者,采用如下的方法,先计算出完整列的选择性:

select count(distinct specific_column) / count(0)
from specific_table;

然后分别计算不同前缀的选择性,直到找到与完整列接近的选择性前缀长度即可:

select count(distinct left(specific_column, 3)) / count(0) as sel3,
count(distinct left(specific_column, 4)) / count(0) as sel4,
count(distinct left(specific_column, 5)) / count(0) as sel5,
count(distinct left(specific_column, 6)) / count(0) as sel6,
count(distinct left(specific_column, 7)) / count(0) as sel7
from specific_table;

不过,也有例外的情况,那就是即使现在我们选择了比较接近完整列选择性的前缀,但数据的分布仍然很不均匀。

这时我们需要用该前缀执行如下查询,并与完整列查询出的数目作比较,观察这些出现频率最高的前缀值与完整列出现频率是否接近,否的话需要再将前缀值调大。

select count(0) as c, left(specific_column, 5) as pref
from specific_table
group by pref
order by c desc
limit 10;

-- 完整列的出现频率
select count(0) as c, specific_column
from specific_table
group by specific_column
order by c desc
limit 10;

最后,找到合适的前缀数创建前缀索引可以使用如下 SQL:

alter table specific_table add index index_specific_column(specific_column(7));

虽然前缀索引能够使索引更小,更快,但是我们不能使用前缀索引做 ORDER BY 和 GROUP BY 操作,也无法使用前缀索引做索引覆盖。

2. 关于索引必须知道的事儿

下文中我们所说的索引如果没有特别指明类型,那么就代表我们说的是 B+ Tree 索引,它使用 B+ Tree 数据结构来保存数据。

B+ Tree 会将所有的数据保存在叶子节点上,并且通过双向链表将叶子节点连接起来。

聚簇索引

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式,InnoDB 聚簇索引在数据页中同时保存索引和数据行,这使得它的数据访问相比于非聚簇索引(二级索引)要快。

聚簇的意思是说 数据行和相邻的键值紧凑的存储在一起,因为无法同时把数据行放在两个不同的地方,所以一个表只能有一个聚簇索引。InnoDB 根据 主键 聚簇数据,如果没有定义主键,InnoDB 会自动生成一个唯一的隐式主键作为聚簇索引。

我们创建一个简单的表,并插入一些数据,来看一下 B+ Tree 索引的数据结构图:

create table demo (
    c1 int,
    c2 int,
    c3 char(1),
    primary key(c1)
)engine=InnoDB;

MySQL 是通过 数据页 来保存数据的,每个页的大小默认为 16KB,在每个数据页中都默认有最小记录 Infimum 和最大记录 Supremum,如下图所示:

BTree.png

我们可以发现在叶子节点中保存了所有数据行,每个页之间通过页文件头部(File Header)记录的双向链表指针进行连接,数据记录之间通过单向链表连接,单向链表的指针记录在每行数据记录的 记录头信息 中。

在非叶子节点中,我们可以发现记录的信息只有 主键值和对应的页号,因此数据页能存放的数据更多,B+ Tree 也就能更加 “矮胖”,这样就能使得磁盘 I/O 更少。一般情况下我们用到的 B+ Tree 不会超过 4 层。

B+ Tree 按照索引列数据的大小顺序排序存储,所以很适合按照范围来查询。每次搜索数据都从索引的根节点开始,通过比较节点中的值和要查找的值来找到合适的指针进入下层子节点,最终在叶子节点中找到或找不到对应的记录。

聚簇索引能够加快我们访问数据的速度,但是它也有一些局限性我们需要了解一下:

  • 聚簇索引最大限度地提高了 I/O 密集型应用的性能,但如果 数据全部都放在内存中,则访问的顺序就没那么重要了,聚簇索引也就没什么优势了

    随着 RAM 变得更便宜,而且许多数据集不是那么大,所以将它们全部保存在内存中是非常可行的,包括可能分布在多个服务器上,这也促进了内存数据库的发展。

  • 插入速度严重依赖于插入顺序。按照主键的顺序插入行是将数据加载到 InnoDB 表中最快的方式。但如果不是按照主键的顺序插入,会因页分裂影响插入速度。最好避免随机的聚簇索引,特别是对于 I/O 密集型的应用

  • 聚簇索引列更新的代价很高,因为它会强制 InnoDB 将每个被更新的行移动到新的位置,这也会发生页分裂,导致性能下降

二级索引

二级索引是非聚簇索引,InnoDB 引擎在 B+ Tree 的叶子节点存储的不是完成的数据记录,而只是 索引列和主键列的值。如果在查询时没有发生覆盖索引的话,需要根据主键值进行回表操作以获取需要的结果。

二级索引是关系型数据库的基础,并且在文档数据库中也很普遍。许多键值存储(如 HBase 和 Volde-mort)为了减少实现的复杂度而放弃了二级索引,但是一些(如 Riak)已经开始添加它们,因为它们对于数据模型实在是太有用了。并且次级索引也是 Solr 和 Elasticsearch 等搜索服务器的基石。

实际上,有两种用二级索引对文档数据库进行分区的方法:基于文档(document-based) 的分区 和 基于关键词(term-based) 的分区。

*基于文档的分区

假设我们有一个汽车销售网站,每条数据都有唯一的 ID,我们称之为文档 ID。我们使用文档 ID 进行分区,并为汽车颜色字段创建二级索引,分区结果如下图所示:

文档分区.png

这样的二级索引分配方法,使得每个分区都是独立的:每个分区自己维护自己的索引,它不关心其他分区的数据,这种文档分区索引也被称为 本地索引

当我们查询红色的汽车时,需要将请求发布到所有的分区,并合并所有返回的结果,这种查询数据库的方法被称为 分散/聚集,可能会使得二级索引查询数据比较耗时。

*基于关键词的分区

我们也可以构建一个覆盖所有分区数据的 全局索引,比如我们将 a 到 r 开头的颜色的二级索引保存在分区 0 中,将 s 到 z 的保存在分区 1 中,如下图所示:

关键词分区.png

我们将这种分区方法称为 关键词分区,根据关键词本身分区对于范围扫描非常有用,比如说我现在想获取 a 到 r 开头的颜色的所有汽车数据;而对关键词的哈希分区又能够提供分区负载均衡的能力。

基于关键词分区的全局索引优于文档分区索引的地方在于它的读取更加高效,并不需要将请求打到所有分区上,只需要将请求发送到含有对应关键词的分区即可,而它的缺点在于对单个分区文档的写入可能会产生多个分区的索引的数据变更,需要协调跨分区的分布式事务。

覆盖索引

覆盖索引可以简单地理解成 查询只需要访问索引列而无需访问其他数据列

优秀的索引设计不单单只考虑 WHERE 条件,也会根据想要查询的列去综合分析。如果只需要索引列的话,那么覆盖索引是非常有用的工具,它能避免回表操作,这样 MySQL 就会极大地减少数据访问量,而且索引占用的空间很小,将这些数据缓存在内存中的压力远小于缓存所有相关数据行。

如果业务无需查询其他列,那么我们最好把业务需要的列放在查询列表中,以实现覆盖索引,而不是简单地以 * 来替代;在某些情况下,可以根据想要查询的列,对所使用的索引进行扩展,即增加想要查询的列达到覆盖索引的目的。

当执行一个覆盖索引的查询时,在 EXPLAIN 的 Extra 列可以看到 Using index 的信息。

自适应哈希索引

它是 InnoDB 的一个特性,当 InnoDB 发现某些索引值被非常频繁的访问时,它会在原有的 B+ Tree 索引之上,再在内存中构建一个哈希索引,以此来加快对应数据的访问。这个过程是自动化的,我们无法进行干预,不过可以通过参数配置将其关闭。


巨人的肩膀

  • 《数据密集型应用系统设计》:第三章、第六章
  • 《高性能 MySQL 第四版》:第七章
  • 《MySQL 是怎样运行的》:第四、五、六、七章
  • 14.6.2.4 InnoDB Full-Text Indexes

作者:京东物流 王奕龙

来源:京东云开发者社区 自猿其说Tech 转载请注明来源

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

高性能MySQL实战(二):索引 的相关文章

  • PDO PHP 连接,致命错误

    我的连接类 firstcode php class DB functions public db function construct try db new PDO mysql localhost dbname xxx charset ut
  • 无法获取log.d或输出Robolectrict + gradle

    有没有人能够将 System out 或 Log d 跟踪从 robolectric 测试输出到 gradle 控制台 我在用Robolectric Gradle 测试插件 https github com robolectric robo
  • 如何以编程方式检查 AndroidManifest.xml 中是否声明了服务?

    我正在编写一个库 该库提供了一项服务 其他开发人员可以通过将其包含在他们的项目中来使用该服务 因此 我无法控制 AndroidManifest xml 我在文档中解释了要做什么 但一个常见的问题是人们忽略了将适当的 标记添加到其清单中 或者
  • 是否可以将数组或对象添加到 Android 上的 SharedPreferences

    我有一个ArrayList具有名称和图标指针的对象 我想将其保存在SharedPreferences 我能怎么做 注意 我不想使用数据库 无论 API 级别如何 请检查SharedPreferences 中的字符串数组和对象数组 http
  • Android 模拟器插件无法初始化后端 EGL 显示

    我在 Cloudbees 上设置了 Jenkins 作业 并且可以在那里成功签出并编译我的 Android 项目 现在我想在 android 模拟器中运行一些 JUnit 测试并添加 Android 模拟器插件 我将 显示模拟器窗口 选项设
  • CollapsingToolBarLayout - 状态栏稀松布颜色不改变

    几天前我更新了我的 android studio 并开始使用 CoordinatorLayout 和 CollapsingToolbarLayout 只是尝试一些东西 工具栏稀松布颜色似乎覆盖了状态栏初始颜色和状态栏稀松布颜色 从 xml
  • 是否必须删除 Intent extra?

    这可能是一个愚蠢的问题 但是是否有一条规则规定消费活动必须显式删除 Intent 额外内容 或者只有在回收 Intent 对象时才如此 换句话说 如果我总是通过执行以下操作来链接到下一个活动 Intent i new Intent MyCu
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 无法访问 com.google.android.gms.internal.zzbfm 的 zzbfm 类文件未找到

    我正在将我的 Android 应用程序项目从GCM to FCM 为此 我使用 Android Studio 中的 Firebase 助手工具 并遵循 Google 开发人员指南中的说明 一切都很顺利 并将我的应用程序代码更改为FCM根据助
  • 尝试将相机切换回前面但出现异常

    尝试将相机切换回前面 但出现异常 找不到 问题请检查并帮助 error 01 27 11 49 00 376 E AndroidRuntime 30767 java lang RuntimeException Unable to start
  • 是否有 ADB 命令来检查媒体是否正在播放

    我想使用 ADB 命令检查根植于终端的外部设备中是否正在播放音频 视频 我无法找到任何 ADB 命令 如果有 我尝试过 adb shell dumpsys media player 我想要一个命令来指定视频是否正在运行 您可以使用以下命令查
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • 一次从多个表中删除行

    我正在尝试将 2 个查询合并为一个这样的查询 result db gt query DELETE FROM menu WHERE name new or die db gt error result db gt query DELETE F
  • 在 SQLite 中搜索时排除 HTML 标签和一些 UNICODE 字符

    更新 4 我已经成功运行了firstchar例如 但现在的问题是使用regex 即使包含头文件 它也无法识别regex操作员 有什么线索可以解决这个问题吗 更新 2 我已经编译了sqlite3我的项目中的库 我现在正在寻找任何人帮助我为我的
  • 在 android DatePickerDialog 中将语言设置为法语

    有什么办法可以让日期显示在DatePickerDialog用法语 我已经搜索过这个但没有找到结果 这是我的代码 Calendar c Calendar getInstance picker new DatePickerDialog Paym
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 增加活动的屏幕亮度

    显然 Android 操作系统中至少有三种不同的技术可以改变屏幕亮度 其中两个在纸杯蛋糕之后不再起作用 而第三个被接受的技术显然有一个错误 我想在单视图活动开始时增加屏幕亮度 然后在活动结束时将亮度恢复为用户设置 没有按钮 没有第二个视图或
  • 在activity_main.xml中注释

    我是安卓新手 据我所知 XML 中的注释与 HTML 中的注释相同 使用 形式 我想在 Android 项目的 Activity main xml 配置文件中写一些注释 但它给了我错误 值得注意的是 我使用的是 Eclipse 但目前 我直
  • Android:膨胀布局时出现 StackOverFlowError 和 InvokingTargetException

    首先 对不起我的英语 我在膨胀布局时有一个问题 我有一个自定义视图 从 LinearLayout 扩展而来 称为按钮帮助 我在名为的布局上使用该视图加载活动 我的以下代码在所有设备和模拟器上都能完美运行 但具有 QVGA 屏幕 例如 Sam
  • 将两个文本视图并排放置在布局中

    我有两个文本视图 需要在布局中并排放置 并且必须遵守两条规则 Textview2 始终需要完整显示 如果布局中没有足够的空间 则必须裁剪 Textview1 例子 文本视图1 文本视图2 Teeeeeeeeeeeeeeeeeextview1

随机推荐

  • matlab 怎么使用function,Matlab怎么调用函数 自定义函数使用方法

    Matlab作为一款专业性极强的商业数学软件 将诸多的算法开发 统计分析 数据可视化功能融入其中 用户可以方便地调用需要的函数 建立数学模型 为了满足你工作的需要 还可以自行设置自己需要的函数 下面就跟小编了解下吧 类别 理科工具 大小 1
  • Unix Network Programming Episode 77

    gethostbyaddr Function The function gethostbyaddr takes a binary IPv4 address and tries to find the hostname correspondi
  • time_wait的快速回收和重用

    问题现象 PC与工控机之间通信 工控机发送SYN PC一直回复FIN或者RST 问题解释 1 time wait产生的原因及作用 下面我们先来简单回顾一下TCP连接关闭动作 在Linux环境下我们可以如下的方式来统计TCP连接的情况 net
  • 高防服务器如何防止网站攻击,高防服务器怎么防御攻击的?

    高防服务器怎么防御攻击的 高防服务器 从字面上来理解就是具备防御性能的服务器 高防服务器相较于普通的服务器除了超高的防御性能以外 在配置上通常也是比较高的 所以在使用上 会更稳定一些 所以深受各类行业站长的喜爱 如今 很多企业在选择租用服务
  • C语言之冒泡排序法

    首先 还是老规矩先上代码 include
  • 数组双指针法汇总

    指针移动方向 相向夹逼 同向移动 维护的是一个区间还是只是关心指针指向的两个元素 同向移动的 维护一个区间的双指针法即滑动窗口法 2Sum 排序后两头往中间夹逼的双指针法 指针为什么可以不回退 即为什么可以i只 j只 当A i A j
  • jvm学习——7.运行时数据区之堆

    一个进程对应一个jvm实例 一个运行时数据区 又包含多个线程 这些线程共享了方法区和堆 每个线程包含了程序计数器 本地方法栈和虚拟机栈 66 核心概述 1 一个jvm实例只存在一个堆内存 堆也是java内存管理的核心区域 2 Java堆区在
  • kuboard获取token命令

    输入命令查看 echo kubectl n kube system get secret kubectl n kube system get secret grep kuboard user awk print 1 o go templat
  • u8系统怎么连接服务器,u8客户端连接服务器流程

    u8客户端连接服务器流程 内容精选 换一换 请点击下载 下载并安装桌面版客户端 您已经从企业的会议管理员那儿获取用户帐号了吗 快使用用户帐号登录客户端 开启会议之旅 桌面客户端定位基于电脑使用 在会议室中不支持接入鹅颈麦克风 音箱等外设使用
  • QT的QListWidget之单击双击增删改详解

    QListWidget是列表框控件 它是通过QListWidgetItem列表项来进行操作 我们的增删改操作也是围绕着它来开展 需要注意的是 删除操作 需要先断开QListWidget的信号和槽连接 否则会程序崩溃 void MainWin
  • opencv畸变校正的两种方法

    opencv中畸变校正有两种方法 1 undistort 直接进行畸变校正 void cv undistort InputArray src 原始图像 OutputArray dst 矫正图像 InputArray cameraMatrix
  • echarts中的地图展示所有省份以及悬浮上去展示具体的信息

  • stm32 HAL库 Flash操作简介

    stm32 HAL库 Flash操作简介 目录 第一stm32 flash介绍 查看代码段 以判断代码长度 flash的基本操作规则 stm32 HAL库 Flash操作指南 stm32f1xx hal flash c stm32f1xx
  • 在家做什么手工赚钱,这5种比较适合在家操作!

    对于很多怀孕的女生来说 呆在家里确实很无聊 大部分人呆在家里只能看看电视 玩玩手机 很多的孕妈都会抱怨 真是无聊透了 所以对于很多的孕妈来说 都想找点事做来缓解自己无聊的情绪 避免得了抑郁症 给宝宝带来不好的环境 那么怀孕在家里 有什么轻松
  • SpringSecurity的使用和流程详解(二)

    文章目录 登录 准备工作 核心代码 校验 准备工作 核心代码 测试 退出登录 登录 准备工作 添加依赖
  • 线程池代码

    线程池 Global h pragma once const int DEFAULT POOL SIZE 10 const int STARTED 0 const int STOPPED 1 Mutex h pragma once incl
  • 鸡肋的RDP反制

    更新时间 2023年07月19日09 18 29 为什么叫鸡肋 鸡肋者 食之无肉 弃之有味 你说不能成吧 但是有成功案例 你说成了吧 要求太高 还要看运气的 一句话 对方需要开启磁盘共享 不开启 没办法反制 1 背景介绍 在很多攻防中 蓝队
  • 向量叉乘判断顺时针还是逆时针

    可以通过向量的叉乘判断一条线旋转的过程是顺时针还是逆时针的 有两个向量AB和AC 将两个向量进行叉乘 direct AB x AC 当direct gt 0时 为逆时针旋转 当direct lt 0时为顺时针旋转 当写类似于旋转按钮的控件的
  • 螺纹检测案例-螺距测量-大径小径检测-螺牙检测

    齿轮检测分析 Gear inspection and analysis 螺纹结构及检测要素 1 大径 宽径 2 小径 窄径 3 中经 4 螺距 间距 5 螺牙高度 深度 VisionBank 软件螺纹检测工具 02 01 螺纹检测分析流程
  • 高性能MySQL实战(二):索引

    我们在上篇 高性能MySQL实战 一 表结构 中已经建立好了表结构 这篇我们则是针对已有的表结构和搜索条件为表创建索引 1 根据搜索条件创建索引 我们还是先将表结构的初始化 SQL 拿过来 CREATE TABLE service log