• [技术干货] SpringCloud-RabbitMQ消息模型-转载
     本文深入介绍了RabbitMQ消息模型,涵盖了基本消息队列、工作消息队列、广播、路由和主题等五种常见消息模型。每种模型都具有独特的特点和适用场景,为开发者提供了灵活而强大的消息传递工具。通过这些模型,RabbitMQ实现了解耦、异步通信以及高效的消息路由,为分布式系统的开发和部署提供了可靠的基础。阅读本文,读者将深入了解RabbitMQ不同消息模型的应用场景和使用方法,为构建可靠的消息传递系统提供了有益的指导。  一、RabbitMQ消息模型介绍 RabbitMQ 是一种高度可扩展的消息代理,其消息模型基于 AMQP(Advanced Message Queuing Protocol)协议,提供了灵活可靠的消息传递机制。  以下是 RabbitMQ 的核心消息模型组成部分:  组成部分    功能 生产者 (Producer)    生产者负责产生和发送消息到 RabbitMQ 服务器。 将消息发布到特定的交换机(Exchange)。 交换机 (Exchange)    交换机是消息的分发中心,接收生产者发送的消息,并将其路由到一个或多个队列。RabbitMQ 提供不同类型的交换机,如直连交换机(direct)、主题交换机(topic)、扇出交换机(fanout)、头交换机(headers)等,以满足不同的路由需求。 队列 (Queue)    队列是消息的存储地点,消息在队列中等待被消费。 消息按照一定的规则存储在队列中,等待消费者订阅并处理。 绑定 (Binding)    绑定定义了交换机如何将消息路由到特定的队列。 绑定规则由消费者在订阅队列时指定,确保消息按照预期的方式路由。 消费者 (Consumer)    消费者订阅一个或多个队列,接收并处理队列中的消息。消费者从队列中获取消息,完成相应的业务逻辑,然后应答(acknowledge)消息。 路由键 (Routing Key)    路由键是消息从生产者到达交换机时的附加信息,用于指导消息路由到特定的队列。路由键的值与交换机类型和绑定规则相关。 RabbitMQ 的消息模型允许灵活的消息路由和传递,提供了高度可靠性和可伸缩性。生产者通过交换机将消息发送到队列,而消费者则订阅队列并处理消息。这种模型使得系统能够实现解耦、异步通信,同时确保消息在分布式环境中的可靠传递。  二、RabbitMQ常见消息模型 MQ(消息队列)在应用中有多种常见的消息模型,其中包括以下五种:  1、基本消息队列 基本消息队(Basic Queue) 列是最简单的消息传递模型。在这个模型中,生产者发送包含简单信息如 "Hello World!" 的消息到队列,而消费者则接收并处理这些消息。这种模型适用于简单的场景,如需要一对一通信的情况。  示意图:   2、工作消息队列 工作消息队列(Work Queue)用于在多个工作者(消费者)之间分发任务。生产者将任务发送到队列,多个工作者可以并发地处理这些任务。这种模型有效地实现了任务的分发和并行处理。  示意图:   3、发布订阅 发布订阅(Publish/Subscribe) 模型采用广播方式,生产者将消息发送到交换机,多个队列通过订阅交换机接收消息,实现一对多的消息传递。   根据交换机类型不同,发布订阅模型又分为三种:  ① 广播交换机(Fanout Exchange) 广播交换机(Fanout Exchange)是一种简单而强大的消息传递模型。当生产者发送消息到Fanout Exchange时,该交换机会将消息广播到所有与之绑定的队列,无论它们的路由键是什么。这使得多个队列能够同时接收相同的消息,实现了一对多的消息传递  示意图:   ② 直连交换机(Direct Exchange) 直连交换机(Direct Exchange)通过使用指定的路由键,将消息传递到与之匹配的队列。这种模型适用于需要将消息精确路由到特定队列的场景。生产者发送消息时,可以指定一个或多个路由键,而队列在绑定交换机时也需要指定相应的路由键,从而实现精准的消息路由。  示意图:   ③ 主题交换机(Topic) 主题交换机(Topic Exchange)允许消息的路由键与队列的绑定模式进行模糊匹配,从而实现更灵活的消息订阅和路由。路由键可以使用通配符(和#),其中星号()代表一个单词,井号(#)代表零个或多个单词。这种模型使得队列能够订阅符合特定模式的消息,而不仅仅是固定的路由键。  示意图:   这五种消息模型展示了RabbitMQ在不同场景下的应用,为开发者提供了多样的选择,以满足各种消息传递需求。    三、RabbitMQ消息模型总结 RabbitMQ作为高度可扩展的消息代理,其消息模型基于AMQP协议,提供了强大的消息传递机制。核心组成部分包括生产者、交换机、队列、绑定和消费者等。消息模型允许实现灵活的消息路由和传递,提供了高度可靠性和可伸缩性。通过交换机将消息发送到队列,消费者订阅队列并处理消息,实现了解耦、异步通信,确保消息在分布式环境中的可靠传递。 ​ ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/weixin_41793160/article/details/136466366 
  • [技术干货] MySQL 篇-深入了解 DDL 语言(一)-转载
         1.0 MySQL 说明         MySQL 是一种关系型数据库管理系统,它支持使用 SQL(Structured Query Language)来管理和操作数据库。SQL 是一种标准化的数据库查询语言,包括 DDL、DML、DQL、DCL 和 TCL等不同类型的语句。          2.0 DDL 语言         DDL 是数据定义语言(Data Definition Language)的缩写,是一种用于定义数据库结构和模式的语言。DDL 包括创建、修改和删除数据库表、视图、索引等数据库对象的语句。常见的 DDL 语句包括 CREATE、ALTER 和 DROP 等。因此,DDL 不是一种独立的编程语言,而是用于管理数据库结构的语言。简单来说, DDL 就是对数据库、表进行增加、删除、查询、修改。          2.1 DDL 语言 - 定义数据库         用 DDL 语言来对数据库的操作主要有一下四点:创建数据库、查询当前的数据库、使用指定的数据库、删除数据库。          2.1.1 创建数据库操作 创建数据库的 SQL 语句为:  create database [ if not exists ] 数据库名;         对于 [ if not exists ] ,翻译为:"如果改数据库不存在" 。这段代码可写可不写,没有强制要求。主要区别是,若没有加上这段代码且存在该数据库,则会报错;若加上这段代码且存在该数据库。则不会报错。           已知已经存在 db01 这个数据库了,通过 create database db01; 再来创建时,会报错。如果加上 if not exists ,那么及时创建相同的数据库也不会报错,当然也不可能创建一个一摸一样的数据库。          2.1.2 查看数据库操作 查看全部数据库的 SQL 语句:   show databases;         需要注意的是,这里的 databases 记得加上 s 且该后面结尾加上 ";" 。   查看的结果为:           在红色框里面的数据库是 MySQL 自带的数据库,万万不可对这四个数据库进行任何危险操作。否则 MySQL 出现问题,需要重新安装了。          除了这个查看全部数据库操作之外,还有查看当前使用数据库操作。   查看当前数据库的 SQL 语句:  select database();         这里的 database 是没有加上 s 的且注意是加上 () 。  操作结果为:           当前使用的数据库为 db01 。          2.1.3 使用数据库操作 使用数据库的 SQL 语句:  use 数据库名;         简单来说,就是选择指点的数据库。  操作结果为:           2.1.4 删除数据库操作 删除数据库的 SQL 语句:  drop database if exists 数据库名;         若存在该数据库,删除不会报错;如果没有加上 if exists 这段代码,那么当不存在该数据库而要删除该数据库时,会报错。  操作结果为:           删除该数据库后,查看全部数据时,不存在 db01 这个库了。显然是删除成功了。          2.2 DDL 语言 - 定义表格         在对表进行操作之前,需要先选择数据库。DDL 来定义表格的操作有:创建表格、查询表格、修改表格、删除表格。          2.2.1 创建表格操作         1)在创建表格之前,先来简单了解约束          约束概念:约束是作用与表中字段上的规则,用于限制存储在表中的数据。          约束目的:保证数据中数据的正确性、有效性和完整性。  约束类型如下:           2)在创建表格之前,再来简单了解数据类型          数据类型可以简单理解为,该字段需要存储空间的大小。总共分为三大类:数值类型、字符串类型、日期时间类型。  数值类型如图:    字符串常见类型如图:           两者区别:举例子 char(10) 与 varchar(10) ,对于 char(10) 来说,不管空间是否占满,都要消耗 10 个字节大小的空间。而对于 varchar(10) 来说,若空间没有占满 10 个字节大小,就会按照消耗实际存储空间大小。  日期时间类型如图:   3)创建表格的 SQL 语句:  create table 表名(     字段 1 字段类型 [约束] [ comment 字段1注释 ],       ......          字段 n 字段类型 [约束] [ comment 字段n注释]  ) [comment 表注释]; 实际例子演示:   create table tb_user(     id tinyint unsigned auto_increment primary key comment '唯一标识',     username varchar(20) not null unique comment '用户名',     name varchar(20) not null comment '名字',     age tinyint unsigned comment '年龄',     gender char(1) default '男' comment '性别,默认为男性' )comment '用户表'; 操作结果为:           这就可以得到一个表格。之后就可以在表格中添加数据了。          2.2.2 查询表格操作 查询当前该数据库中的全部表的 SQL 语句:  -- 查看表 show tables; 操作结果为:   查询该表的结构的 SQL 语句:  -- 查看表的结构 desc 表名; 操作结果为:           注意查询两者的区别:一个是查询所有的表、另一个是查询指定表的结构。          2.2.3 删除表格操作 删除表格的 SQL 语句为:  -- 删除表 drop table 表名;         2.2.4 修改表格操作 1)添加字段的 SQL 语句:  alter table 表名 add 字段名 类型 [约束];  2)修改字段类型的 SQL 语句:  alter table 表名 modify 字段名 新数据类型; 3)修改字段名和字段类型的 SQL 语句:  alter table 表名 change 旧字段名 新字段名 类型 [约束]; 4)删除字段的 SQL 语句:  alter table 表名 drop column 字段名; 5)修改表名的 SQL 语句:  rename table 旧表名 to 新表名;  结合以上操作举个修改例子:  -- 增加表中的列 alter table tb_user add qq char(10) comment 'QQ号';   -- 修改字段类型 alter table tb_user modify qq char(22);   -- 修改字段名和字段类型 alter table tb_user change qq qq_name char(20);   -- 删除表中的指定的字段 alter table tb_user drop column qq_name;   -- 修改表中的名字 rename table tb_user to tb_user2; rename table tb_user2 to tb_user; ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/Tingfeng__/article/details/136288617 
  • [技术干货] SQL Server 事务日志文件过大 解决方案-转载
     事务日志文件(Transaction Log File)是用来记录数据库更新情况的文件,扩展名为ldf。当出现以下情况时,就会报“事务日志已满”的错误:  日志文件没有设置了自动增长,当记录超过初始大小;  日志文件设置了自动增长,“最大文件大小”设置了具体的大小(如2000M),当文件达到设置的大小时。  解决SQL Server数据库事务日志已满的方法 要解决事务日志已满的问题,可以采用以下三种方法,截断日志、收缩日志文件以及修改数据库恢复模式.  修改数据库恢复模式 将数据库恢复模式从“完整模式”或“大容量日志恢复模式”更改为“简单模式”可以解决SQL Server数据库事务日志已满问题。但是,请注意这种方法可能会导致数据丢失。以下是修改数据库恢复模式的步骤:  1. 在 SQL Server Management Studio 中,右键单击数据库,选择“属性”。   2. 在“选项”中,将“恢复模式”设置为“简单”,然后点击“确定”   3. 在 SQL Server Management Studio 中,右键单击数据库,选择“任务”->“备份”。   4. 在“备份类型”中,选择“日志”,点击“确定”。   截断日志 截断日志是解决SQL Server数据库事务日志已满问题的较简单方法。通过截断日志,可以清除日志文件中的旧数据,从而释放空间。  在对象资源管理器中,连接到 SQL Server 数据库引擎的实例,然后展开该实例。 展开“数据库”,再右键单击要截断日志的数据库。 指向“任务”,指向“收缩”,然后选择“文件”。 选择文件的文件类型。可用的选项包括“数据”和“日志”文件。默认选项为“数据”。 在与以上所选的“文件类型”相关联的文件组列表中选择文件组。 从所选文件组和文件类型的可用文件列表中选择文件。 选中“释放未使用的空间”选项,将为操作系统释放文件中所有未用空间,并尝试将行重新定位到未分配页。 根据需要,输入在收缩数据库后数据库文件中要保留的最大可用空间百分比。值可以介于 0 和 99 之间。 请注意,在收缩日志文件之前,需要将数据库的恢复模式更改为简单模式。此外,收缩日志文件的步骤与截断日志文件的步骤类似,但是收缩日志文件会将日志文件的大小缩小到指定的大小,而截断日志文件只是删除不活动的虚拟日志文件以释放空间。  总之,使用 SQL Server Management Studio 截断日志的方法包括连接到 SQL Server 数据库引擎的实例,展开“数据库”,右键单击要截断日志的数据库,指向“任务”,指向“收缩”,然后选择“文件”。请注意,在执行截断操作之前,应该备份数据库以防止数据丢失。  收缩日志文件 收缩日志文件是另一种解决SQL Server数据库事务日志已满问题的方法。通过收缩日志文件,可以压缩日志文件的大小,从而释放空间。  在 SQL Server 中,可以使用 SQL Server Management Studio 或 Transact-SQL 来收缩数据或日志文件。以下是使用 SQL Server Management Studio 收缩日志文件的步骤:  在对象资源管理器中,连接到 SQL Server 数据库引擎的实例,然后展开该实例。  展开“数据库”,再右键单击要收缩的数据库。  指向“任务”,指向“收缩”,然后选择“文件”。   选择文件的文件类型。可用的选项包括“数据”和“日志”文件。默认选项为“数据”。  在与以上所选的“文件类型”相关联的文件组列表中选择文件组。  从所选文件组和文件类型的可用文件列表中选择文件。  选中“释放未使用的空间”选项,将为操作系统释放文件中所有未用空间,并尝试将行重新定位到未分配页。  根据需要,输入在收缩数据库后数据库文件中要保留的最大可用空间百分比。值可以介于 0 和 99 之间。  请注意,收缩日志文件的步骤与收缩数据文件的步骤略有不同。在收缩日志文件之前,需要将数据库的恢复模式更改为简单模式。以下是使用 Transact-SQL 收缩日志文件的步骤:  将数据库的恢复模式更改为简单模式。 截断事务日志。 收缩日志文件。 具体的 Transact-SQL 命令如下:  -- 将数据库的恢复模式更改为简单模式 ALTER DATABASE database_name SET RECOVERY SIMPLE; -- 截断事务日志 BACKUP LOG database_name WITH TRUNCATE_ONLY; -- 收缩日志文件 DBCC SHRINKFILE (file_name, target_size);                      其中,file_name 是要收缩的日志文件的逻辑名称,target_size 是要收缩到的目标大小。  总之,收缩日志文件的步骤包括将数据库的恢复模式更改为简单模式、截断事务日志、收缩日志文件。请注意,在执行收缩操作之前,应该备份数据库以防止数据丢失。  使用傲梅企业备份网络版软件备份 SQL Server 数据库并解决事务日志已满问题 如果您的 SQL Server 数据库事务日志已满,并且您正在使用 SSMS 解决该问题,您也可以考虑使用傲梅企业备份网络版软件来备份数据库。傲梅企业备份网络版提供了以下功能:  ◉ 提供系统/磁盘/分区/文件备份,助您创建集中备份对于 LAN 内的所有客户端。它还提供 SQL Server 备份,用于在一台 PC/服务器上备份多个实例。 ◉ 它使您能够使用计划功能创建自动备份任务。有四种可用的计划模式:一次、每日、每周和每月。 ◉ 支持SQL Server 2019/2017/2016/2014/2012/2008(R2)/2005数据库备份。 ◉ 它可以安装在Windows Server(Windows Server 2019/2016/2012/2011/2008/2003等)和Windows PC(Windows 10/8.1/8/7/Vista/XP)上。  使用傲梅企业备份网络版软件备份 SQL Server 数据库可以帮助您解决事务日志已满的问题。下面是使用傲梅企业备份网络版备份 SQL Server 数据库的步骤:  1. 在局域网内的其中一台计算机上安装傲梅企业备份网络版作为中央管理计算机。  2.安装客户端程序  启动傲梅企业备份网络版 并转到 "计算机"  >  "未控制的计算机"  >  "安装客户端"。您将看到如下两个选项:  客户端手动安装:点击“下一步”即可得到客户端程序安装文件。将安装文件复制到装有 SQL Server 的计算机上,并以管理员身份运行它以安装傲梅企业备份网络版 Agent。  远程客户端安装:点击“下一步”,您将拥有局域网内所有可用的计算机。选择装有SQL Server 的计算机,输入它的用户名和密码,然后单击“安装”。   3.请求控制  3.1. 如果您手动安装了客户端程序,客户端计算机将列在 "计算机"  >  “未控制的计算机”下。勾选装有SQL Server的电脑,点击 “请求控制” 获取控制权限。 提供了两种方法:  输入账号:输入客户端的用户名和密码,点击“确定”。  通过发送消息:程序将向客户端计算机发送消息。在客户端计算机上单击“同意”以授权访问。   3.2. 如果您远程安装了客户端程序,客户端计算机将列在 "计算机"  >  “已控制的计算机”下。在这种情况下,您无需请求控制权。  现在您可以通过 傲梅企业备份网络版每天执行SQL Server自动备份,步骤如下:  1. 转到 “任务” 选项卡,单击 “新建任务” 并选择 “SQL Server 备份”。   2. 在弹出窗口中,根据需要编辑任务名称。然后, 在“第一步”栏中点击 “添加计算机” ,选择带有SQL Server数据库的受控计算机。    3. 单击“步骤 2”列,然后单击“添加”。该程序将检测计算机上的所有 SQL Server 实例。选择要备份的实例和数据库,然后单击“确定”。   4. 单击“第 3 步”列,然后单击“添加存储”。键入网络共享或 NAS 路径以添加目标位置以存储备份文件。   5. 单击左下角的“计划并选择您要为其创建计划的计算机”。在“日程设置”窗口的下拉列表中选择“每天” ,完成相应的设置。您还可以通过单击“高级”选择运行完整/差异备份。   6. 确认操作,点击 “开始备份”。您可以在此处选择“仅创建任务”或“创建并执行任务”。   结论 以上是解决 SQL Server数据库事务日志已满问题的多种方法。截断日志和收缩日志文件是较为简单的方法,但可能会导致数据丢失。修改数据库恢复模式可以解决问题,但也可能会导致数据丢失。使用傲梅企业备份网络版软件备份 SQL Server 数据库是最安全的方法,可以保证数据的完整性。 ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/qq_41497074/article/details/131675312 
  • [技术干货] 【MySQL】学习多表查询和笛卡尔积-转载
     多表查询 指的是从多张表中查询数据  首先准备好需要查询的数据表 - dept表 和 emp表 -- 准备数据 create table dept(     id int auto_increment comment 'ID' primary key ,     name varchar(50) not null comment '部门名称' )comment '部门表'; insert into  dept(id, name) VALUES (1,'研发部'),(2,'市场部'),(3,'财务部'),(4,'销售部'),(5,'总经办'),(6,'人事部');  create table emp(     id int auto_increment comment 'ID' primary key ,     name varchar(50) not null comment '姓名',     age int comment '年龄',     job varchar(20) comment '职位',     salary int comment '薪资',     entrydate date comment '入职时间',     managerid int comment '直属领导ID',     dept_id int comment '部门ID' )comment '员工表';  insert into emp (id, name, age, job, salary, entrydate, managerid, dept_id) VALUES                 (1,'金庸',66,'总裁',2000,'2000-01-01',null,5),(2,'张无忌',20,'项目经理',12500,'2005-12-05',1,1),                 (3,'杨逍',33,'开发',8400,'2000-11-03',2,1),(4,'韦一笑',48,'开发',11000,'2002-02-05',2,1),                 (5,'常遇春',43,'开发',10500,'2004-09-07',3,1),(6,'小昭',19,'程序员鼓励师',6600,'2004-10-12',2,1),                 (7,'灭绝',60,'财务总监',8500,'2002-09-12',1,3),(8,'周芷若',19,'会计',48000,'2006-06-02',7,3),                 (9,'丁敏君',23,'出纳',5250,'2009-05-13',7,3),(10,'赵敏',20,'市场部总监',12500,'2004-10-12',1,2),                 (11,'鹿杖客',56,'职员',3750,'2006-10-03',10,2),(12,'鹤笔翁',19,'职员',3750,'2007-05-09',10,2),                 (13,'方东白',19,'职员',5500,'2009-02-12',10,2),(14,'张三丰',88,'销售总监',14000,'2004-10-12',14,4),                 (15,'俞莲舟',38,'销售',4600,'2004-10-12',14,4),(16,'宋远桥',40,'销售',4600,'2004-10-12',14,4),                 (17,'陈友谅',42,null,2000,'2011-10-12',1,null);  -- 添加外键将两张表进行关联 alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id); -- 多表查询 - 笛卡尔积 select * from emp , dept ; 笛卡尔积:笛卡尔乘积是指在数学中,两个集合 A 集合和 B集合的所有组合情况。(在多表查询时,需要消除无效的笛卡尔积)—>17*6 = 102 所以我们可以看到102条记录  如何消除无效的笛卡尔积? 我们可以通过emp表中的外键和dept的id建立连接,我们只需要在原来基础上加上条件即可 -- 多表查询 - 通过where添加条件,消除无效的笛卡尔积 select * from emp , dept where emp.dept_id = dept.id ; 通过控制台运行结果我们可以发现我们明明有17个员工而查询到的结果只有16条,这是为什么呢? 这是因为我们的陈友谅这个员工是刚来的员工还没有给他分配部门。👇  多表查询分类 连接查询 内连接: 相当于查询A、B交集部分数据 外连接: 左外连接:查询 左表 所有数据,以及两张表交集部分数据 右外连接:查询 右表 所有数据,以及两张表交集部分数据 自连接: 当前表与自身的连接查询,自连接必须使用表别名。 字查询                          原文链接:https://blog.csdn.net/Aileenvov/article/details/136153617 
  • 项目开发中常用乱码解决手段分享
    在做项目的过程中,遇到了中文乱码问题,该如何处理?(比如网站主页查询页面显示乱码)可以从页面,程序,以及数据库三个方面去查看问题的原因所在,主页面显示中文乱码,无外乎是因为从数据库中取出来的数据传输到主页面的过程中出现了编码问题,那么就应该从这三个方面去查找问题的所在。因为我们常用UTF-8的编码格式,所以我们就检查所有数据的编码是否都是UTF-8编码。1.  查看一下页面jsp文件的编码格式(1.3.1/1.3.2)1.1、项目文本文件默认编码:【右击项目】->【Properties】->【Resource】->【Text file encoding】1.2、文件默认编码:默认使用项目的默认编码【右击文件】->【Properties】->【Resource】->【Text file encoding】1.3、JSP文件编码:由于JSP要翻译为Servlet1.3.1、JSP文件编码:【右击文件】->【Properties】->【Resource】->【Text file encoding】1.3.2、JSP翻译为Servlet时的编码: (此项可以由1.1,1.2,1.3.1代替)<%@ page language="java" pageEncoding="utf-8"%>1.3.3、从服务器将jsp内容输出到浏览器<%@page contentType="text/html;charset=utf-8"%>在这次输出过程中,由contentType属性中的charset来指定,将servlet编译后的的二进制码以charset的编码形式来输出。2.  服务器端编码设置服务器端编码,将客户端传过来的数据进行解码:浏览器默认使用ISO-8859-1进行编码数据,然后将数据传输到服务器,因此我们默认只需要将浏览器发送过来的数据转换为我们需要的编码即可。GET请求方式:2.1 TOMCAT默认ISO-8859-1 因此可以设置默认编码为UTF-8解决,在conf\server.xml文件中设置如下<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" URIEncoding=”UTF-8”/>2.2String username = request.getParameter(“username”);username = new String(username.getBytes("ISO-8859-1“), "UTF-8"); POST请求方式:2.3 // 必须在获取参数之前,调用如下方法先解码request.setCharacterEncoding(“UTF-8”);String username = request.getParameter(“username”);response.setContentType("text/html;charset=utf-8");3.数据库的编码设置  3.1 JDBC连接数据库的编码设置    "jdbc:mysql://localhost:3306/jd1203db?useUnicode=true&characterEncoding=utf8","root","1234");  3.2 在建表或者建数据库时可以加上:    create database jsd1203db ENGINE=InnoDB DEFAULT CHARSET=utf8; 3.3查看MySql数据中当前联接系统参数  show variables like 'char%',显示各个编码类型。    可以show create database dangdang;通过该语句查看建库的语句,看是否有设置编码。   如果各种编码都是对的,可是在数据库中查看数据时是乱码,可以用set names ‘gbk’,设置查看编码为gbk,与系统一致(windows)。 注意,这个设置只对当前会话有效。
  • [技术干货] 浅谈为什么现在大多数公司都转向pgsql,而非原来的mysql
    现在大部分应用选择使用 PostgreSQL(常称为 pgsql)而不是 MySQL 的原因有多个,这些原因可能因具体的应用场景、技术要求和团队偏好而异。以下是一些可能的原因:功能特性:扩展性:PostgreSQL 支持更多的数据类型、函数和操作符,允许开发者构建更复杂的应用。事务处理:PostgreSQL 支持更复杂的 ACID 事务模型,对于需要高度一致性和可靠性的应用来说是一个优势。JSON 支持:PostgreSQL 提供了对 JSON 数据的原生支持,这对于存储和查询 JSON 格式的数据非常方便。性能:查询性能:在某些复杂查询和大数据量的情况下,PostgreSQL 可能提供比 MySQL 更好的性能。并行查询:PostgreSQL 支持并行查询,这有助于加速大数据集的处理。标准和兼容性:SQL 标准:PostgreSQL 更接近于 SQL 标准,这有助于跨数据库系统的兼容性。开源社区:虽然 MySQL 也有庞大的开源社区,但 PostgreSQL 社区在某些方面可能更活跃,这有助于解决技术问题。可靠性:数据完整性:PostgreSQL 提供了更强大的数据完整性检查和恢复功能。故障恢复:PostgreSQL 的故障恢复机制也被认为比 MySQL 更健壮。安全性:加密和身份验证:PostgreSQL 提供了更强大的加密和身份验证功能,有助于保护数据安全。行级安全性:PostgreSQL 支持行级安全性,允许开发者更精细地控制数据的访问权限。其他:复制和集群:PostgreSQL 提供了强大的复制和集群功能,有助于构建高可用性和可扩展性的应用。历史和技术债务:某些团队可能因历史项目或技术债务而选择 PostgreSQL,而不是 MySQL。需要注意的是,选择数据库系统是一个复杂的过程,需要考虑多种因素,如技术需求、团队经验、社区支持、成本等。因此,并没有一个“一刀切”的答案,每个项目都应该根据具体情况进行评估和选择。
  • [其他] group by 为什么比 distinct 效率高
    在数据库操作中,我们常常遇到需要将数据去重计数的工作。例如:表A,列colACABCDAB结果就是一共出现4个不同的字母A、B、C、D即结果为4大体上我们可以选择count(distinct col)的方法和group+count的方法。分别为:select count(distinct col) from A;select count(1) from (select 1 from A group by col) alias;两中方法实现有什么不同呢?其实上述两中方法分别是在运算和存储上的权衡。distinct需要将col列中的全部内容都存储在一个内存中,可以理解为一个hash结构,key为col的值,最后计算hash结构中有多少个key即可得到结果。很明显,需要将所有不同的值都存起来。内存消耗可能较大。而group by的方式是先将col排序。而数据库中的group一般使用sort的方法,即数据库会先对col进行排序。而排序的基本理论是,时间复杂为nlogn,空间为1.,然后只要单纯的计数就可以了。优点是空间复杂度小,缺点是要进行一次排序,执行时间会较长。两中方法各有优劣,在使用的时候,我们需要根据实际情况进行取舍。具体情况可参考如下法则数据分布去重方式原因离散groupdistinct空间占用较大,在时间复杂度允许的情况下,group 可以发挥空间复杂度优势集中distinctdistinct空间占用较小,可以发挥时间复杂度优势两个极端:1.数据列的所有数据都一样,即去重计数的结果为1时,用distinct最佳2.如果数据列唯一,没有相同数值,用group 最好当然,在group by时,某些数据库产品会根据数据列的情况智能地选择是使用排序去重还是hash去重,例如postgresql。当然,我们可以根据实际情况对执行计划进行人工的干预,而这不是这里要讨论的话题了。原文:https://blog.csdn.net/qq_40026782/article/details/83416317?spm=1001.2014.3001.5502
  • [其他] 深入理解 MySQL 底层实现
     一、MySQL 的常用引擎 1. InnoDB InnoDB 的存储文件有两个,后缀名分别是 .frm 和 .idb,其中 .frm 是表的定义文件,而 idb 是数据文件。  InnoDB 中存在表锁和行锁,不过行锁是在命中索引的情况下才会起作用。  InnoDB 支持事务,且支持四种隔离级别(读未提交、读已提交、可重复读、串行化),默认的为可重复读;而在 Oracle 数据库中,只支持串行化级别和读已提交这两种级别,其中默认的为读已提交级别。  2. Myisam Myisam 的存储文件有三个,后缀名分别是 .frm、.MYD、MYI,其中 .frm 是表的定义文件,.MYD 是数据文件,.MYI 是索引文件。  Myisam 只支持表锁,且不支持事务。Myisam 由于有单独的索引文件,在读取数据方面的性能很高 。  3. 存储结构 InnoDB 和 Myisam 都是用 B+Tree 来存储数据的。  二、MySQL 的数据、索引存储结构 1. 数据存储的原理(硬盘) 信息存储在硬盘里,硬盘是由很多的盘片组成,通过盘片表面的磁性物质来存储数据。  把盘片放在显微镜下放大,可以看到盘片表面是凹凸不平的,凸起的地方被磁化,代表数字 1,凹的地方没有被磁化,代表数字 0,因此硬盘可以通过二进制的形式来存储表示文字、图片等的信息。  硬盘有很多种,但是都是由盘片、磁头、盘片主轴、控制电机、磁头控制器、数据转换器、接口、缓存等几个部分组成。  所有的盘片都固定在一个旋转轴上,这个轴即盘片主轴。  所有的盘片之间是绝对平行的,在每个盘片的盘面上都有一个磁头,磁头与盘片之间的距离比头发丝的直径还小。  所有的磁头连在一个磁头控制器上,由磁头控制器负责各个磁头的运动,磁头可沿盘片的半径方向移动,实际上是斜切运动,每个磁头同一时刻必须是同轴的,即从正上方往下看,所有磁头任何时候都是重叠的。  由于技术的发展,目前已经有多磁头独立技术了,在此不考虑此种情况。  盘片以每分钟数千转到上万转的速度在高速运转,这样磁头就能对盘片上的指定位置进行数据的读写操作。  由于硬盘是高精密设备,尘埃是其大敌,所以必须完全密封。  2. 数据读写的原理 硬盘在逻辑上被划分为磁道、柱面以及扇区。  磁头靠近主轴接触的表面,即线速度最小的地方,是一个特殊的区域,它不存放任何数据,称为启停区或者着陆区,启停区外就是数据区。  在最外圈,离主轴最远的地方是 “0” 磁道,硬盘数据的存放就是从最外圈开始的。  在硬盘中还有一个叫 “0” 磁道检测器的构件,它是用来完成硬盘的初始定位。  盘面  硬盘的盘片一般用铝合金材料做基片,硬盘的每一个盘片都有上下两个盘面,一般每个盘面都会得到利用,都可以存储数据,成为有效盘面,也有极个别的硬盘盘面数为单数。  每一个这样的有效盘面都有一个盘面号,按顺序从上至下从 0 开始编号。  在硬盘系统中,盘面号又叫磁头号,因为每一个有效盘面都有一个对应的读写磁头,硬盘的盘片组在 2-14 片不等,通常有 2-3 个盘片。  磁道  磁盘在格式化时被划分成许多同心圆,这些同心圆轨迹叫做磁道。  磁道从外向内从 0 开始顺序编号,硬盘的每一个盘面有 300-1024 个磁道,新式大容量硬盘每面的磁道数更多,信息以脉冲串的形式记录在这些轨迹中,这些同心圆不是连续记录数据,而是被划分成一段段的圆弧。  这些圆弧的角速度一样,由于径向长度不一样,所以线速度也不一样,外圈的线速度较内圈的线速度大,即同样的转速度下,外圈在同样时间段里,划过的圆弧长度要比内圈划过的圆弧长度大。  每段圆弧叫做一个扇区,扇区从 1 开始编号,每个扇区中的数据作为一个单元同时读出或写入。  磁道是看不见的,只是盘面上以特殊形式磁化了的一些磁化区,在磁盘格式化时就已规划完毕。  柱面  所有盘面上的同一磁道构成一个圆柱,通常称作柱面。  每个圆柱上的磁头由上而下从 0 开始编号,数据的读 / 写按柱面进行,即磁头读 / 写数据时首先在同一柱面内从 0 磁头开始进行操作,依次向下在同一柱面的不同盘面即磁头上进行操作。  只有在同一柱面所有的磁头全部读 / 写完毕后磁头才转移到下一柱面(同心圆再往里的柱面),因为选取磁头只需要通过电子切换即可,而选取柱面则必须机械切换,电子切换相当快,比在机械上的磁头向邻近磁道移动快得多。  所以,数据的读 / 写按柱面进行,而不按盘面进行,也就是说,一个磁道写满数据后,就在同一柱面的下一个盘面来写,一个柱面写满后,才移到下一个扇区开始写数据,读数据也按照这种方式进行,这样就提高了硬盘的读 / 写效率。  扇区  操作系统以扇区形式将信息存储在硬盘上,每个扇区包括 512 个字节的数据和一些其他信息,一个扇区有两个主要部分:存储数据地点的标识符和存储数据的数据段。  标识符就是扇区头标,包括组成扇区三维地址的三个数字:盘面号,柱面号,扇区号(块号)。  数据段可分为数据和保护数据的纠错码(ECC)。在初始准备期间,计算机用 512 个虚拟信息字节(实际数据的存放地)和与这些虚拟信息字节相应的 ECC 数字填入这个部分。  可以查看一个图《扇区、磁道、盘面 (原理理解篇)》理解  3. 访盘请求完成过程 1)确定磁盘地址(柱面号,磁头号,扇区号),内存地址(源 / 目):  当需要从磁盘读取数据的时候,系统会将数据的逻辑地址传递个磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即确定要读的数据在哪个磁道,哪个扇区。  2)为了读取这个扇区的数据,需要将磁头放到这个扇区上方,为了实现这一点:  A. 首先必须找到柱面,即磁头需要移动对准相应磁道,这个过程叫做寻道,所耗费时间叫做寻道时间。  B. 然后目标扇区旋转到磁头下,即磁盘旋转将目标扇区旋转到磁头下,这个过程耗费的时间叫做旋转时间。  3)即一次访盘请求(读 / 写)完成过程由三个动作组成:  A. 寻道(时间):磁头移动定位到指定磁道。  B. 旋转延迟(时间):等待指定扇区从磁头下旋转经过。  C. 数据传输(时间):数据在磁盘与内存之间的实际传输。  4. 磁盘的读写原理 系统将文件存储到磁盘上时,按柱面、磁头、扇区的方式进行,即最先是第 1 磁道的第一磁头下的所有扇区,然后是同一柱面的下一个磁头……  一个柱面存储满后就推进到下一个柱面,直到把文件内容全部写入磁盘。  系统也以相同的顺序读出数据,读出数据时通过告诉磁盘控制器要读出扇区所在柱面号、磁头号和扇区号(物理地址的三个组成部分)进行。  5. 减少 I/O 的预读原理 由于存储介质的特性,磁盘本身存取就比主存慢很多,再加上机械运动耗费的时间,磁盘的存取速度往往是主存的几百分之一。  因此,为了提高效率,要尽量减少磁盘的 I/O。  磁盘往往不是严格地按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存。  这样做的理论依据是计算机科学中著名的局部性原理:  当一个数据被用到时,其附近的数据一般来说也会被马上使用。  程序运行期间所需要的数据通常比较集中。  由于磁盘顺序读取的效率很高(不需要寻道时间,只需要很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高 I/O 效率。  预读的长度一般为页(Page)的整数倍。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储分割为连续的大小相等的块。  每个存储块称为一页(在许多操作系统中,页的大小通常为 4k),主存和磁盘以页为单位交换数据,当程序要读取的数据不在主存中时,会触发一个缺页异常。  此时系统会向磁盘发出读盘信息,磁盘会找到数据的起始位置并向后连续读取一页或几页的数据载入内存中,然后异常返回,程序继续运行。  6. MySQL 的索引 索引是一种用来实现 MySQL 高效获取数据的数据结构。  我们通常所说的在某个字段上建索引,意思就是让 MySQL 对该字段以索引这种数据结构来存储,然后查找的时候就有对应的查找算法。  建索引的根本目的是为了查找的优化,特别是当数据很庞大的时候,一般的查找算法有顺序查找、折半查找、快速查找等。  但是每种查找算法都只能应用于特定的数据结构之上,例如顺序查找依赖于顺序结构,折半查找通过二叉查找树或红黑树实现二分搜索。因此在数据之外,数据库系统还维护着满足特定查找算法的数据结构。  这些数据结构以某种方式引用数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。  7. MySQL 的 B+Tree 目前大多数数据库系统及文件系统都采用 B-Tree 或其变种 B+Tree 作为索引结构。  B+ 树索引是 B+ 树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引。B+ 树中的 B 代表平衡,而不是二叉。  因为 B+ 树是从最早的平衡二叉树演化而来的。B+ 树是由二叉查找树、平衡二叉树(AVLTree)和平衡多路查找树(B-Tree)逐步优化而来。  二叉查找树:左子树的键值小于根的键值,右子树的键值大于根的键值。  AVL 树:平衡二叉树(AVL 树)在符合二叉查找树的条件下,还满足任何节点的两个子树的高度最大差为 1。  平衡多路查找树(B-Tree):为磁盘等外存储设备设计的一种平衡查找树。  系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一磁盘块中的数据会被一次性读取出来,而不是按需读取。  InnoDB 存储引擎使用页作为数据读取单位,页是其磁盘管理的最小单位,默认 page 大小是 16k。  系统的一个磁盘块的存储空间往往没有这么大,因此 InnoDB 每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小 16KB。  InnDB 在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时如果一个页中的每条数据都能助于定位数据记录的位置,这将会减少磁盘 I/O 的次数,提高查询效率。  B-Tree 结构的数据可以让系统高效的找到数据所在的磁盘块。  为了描述 B-Tree,首先定义一条数据记录为一个二元组 [key, data],key 为记录的键值,对于不同数据记录,key 是互不相同的;data 为数据记录除 key 外的数据。  那么 B-Tree 是满足下列条件的数据结构:  d 为大于 1 的一个正整数,称为 B-Tree 的度。  h 为一个正整数,称为 B-Tree 的高度。  每个非叶子节点由 n-1 个 key 和 n 个指针组成,其中 d<=n<=2d。  每个叶子节点最少包含一个 key 和两个指针,最多包含 2d-1 个 key 和 2d 个指针,叶节点的指针均为 null 。  所有叶节点具有相同的深度,等于树高 h。  key 和指针互相间隔,节点两端是指针。  一个节点中的 key 从左到右非递减排列。  所有节点组成树结构。  每个指针要么为 null,要么指向另外一个节点。  如果某个指针在节点 node 最左边且不为 null,则其指向节点的所有 key 小于 v(key1),其中 v(key1) 为 node 的第一个 key 的值。  如果某个指针在节点 node 最右边且不为 null,则其指向节点的所有 key 大于 v(keym),其中 v(keym) 为 node 的最后一个 key 的值。  如果某个指针在节点 node 的左右相邻 key 分别是 keyi 和 keyi+1 且不为 null,则其指向节点的所有 key 小于 v(keyi+1) 且大于 v(keyi)。  B-Tree 中的每个节点根据实际情况可以包含大量的关键字信息和分支,例:    每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。  两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。  以根节点为例,关键字为 17 和 35,P1 指针指向的子树的数据范围为小于 17,P2 指针指向的子树的数据范围为 17~35,P3 指针指向的子树的数据范围为大于 35。  模拟查找关键字 29 的过程:  根据根节点找到磁盘块 1,读入内存。【磁盘 I/O 操作第 1 次】  比较关键字 29 在区间(17,35),找到磁盘块 1 的指针 P2。  根据 P2 指针找到磁盘块 3,读入内存。【磁盘 I/O 操作第 2 次】  比较关键字 29 在区间(26,30),找到磁盘块 3 的指针 P2。  根据 P2 指针找到磁盘块 8,读入内存。【磁盘 I/O 操作第 3 次】  在磁盘块 8 中的关键字列表中找到关键字 29。   MySQL 的 InnoDB 存储引擎在设计时是将根节点常驻内存的,因此力求达到树的深度不超过 3,也就是说 I/O 不需要超过 3 次。  分析上面过程,发现需要 3 次磁盘 I/O 操作,和 3 次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。  而 3 次磁盘 I/O 操作是影响整个 B-Tree 查找效率的决定因素。  B-Tree 相对于 AVLTree 缩减了节点个数,使每次磁盘 I/O 取到内存的数据都发挥了作用,从而提高了查询效率。  B+Tree 是在 B-Tree 基础上的一种优化,使其更适合实现外存储索引结构,InnoDB 存储引擎就是用 B+Tree 实现其索引结构。  在 B-Tree 中,每个节点中有 key,也有 data,而每一个页的存储空间是有限的,如果 data 数据较大时将会导致每个节点(即一个页)能存储的 key 的数量很小。  当存储的数据量很大时同样会导致 B-Tree 的深度较大,增大查询时的磁盘 I/O 次数,进而影响查询效率。  在 B+Tree 中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储 key 值信息,这样可以大大加大每个节点存储的 key 值数量,降低 B+Tree 的高度。  B+Tree 在 B-Tree 的基础上有两点变化:  数据是存在叶子节点中的;  数据节点之间是有指针指向的。   由于 B+Tree 的非叶子节点只存储键值信息,假设每个磁盘块能存储 4 个键值及指针信息,则变成 B+Tree 后其结构如下图所示:    通常在 B+Tree 上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。  因此可以对 B+Tree 进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。  8. Myisam 中的 B+Tree Myisam 引擎也是采用的 B+Tree 结构来作为索引结构。  由于 Myisam 中的索引和数据分别存放在不同的文件,所以在索引树中的叶子节点中存的数据是该索引对应的数据记录的地址,由于数据与索引不在一起,所以 Myisam 是非聚簇索引。    9. InnoDB 中的 B+Tree InnoDB 是以 ID 为索引的数据存储。  采用 InnoDB 引擎的数据存储文件有两个,一个定义文件,一个是数据文件。  InnoDB 通过 B+Tree 结构对 ID 建索引,然后在叶子节点中存储记录。    若建索引的字段不是主键 ID,则对该字段建索引,然后在叶子节点中存储的是该记录的主键,然后通过主键索引找到对应的记录。  三、MySQL 的相关优化 1. MySQL 性能优化:组成、表的设计 开启查询缓存。避免某些 SQL 函数直接在 SQL 语句中使用,从而导致 Mysql 缓存失效。  避免画蛇添足。目的是什么就取什么,例如某个逻辑是只需要判断是否存在女性,若是查到了一条即可,勿要全部都查一遍,此时要善用 limit。  建合适的索引。所以要建在合适的地方,合适的对象上。经常操作 / 比较 / 判断的字段应该建索引。  字段大小合宜。字段的取值是有限而且是固定的,这种情况下可以用 enum,IP 字段可以用 unsigned int 来存储。  表的设计。垂直分割表,使得固定表与变长表分割,从而降低表的复杂度和字段的数目。  2. SQL 语句优化:避免全表扫描 建索引:一般在 where 及 order by 中涉及到的列上建索引,尽量不要对可以重复的字段建索引。  尽量避免在 where 中使用 !(<>)或 or,也不要进行 null 值判断。  尽量避免在 where 中对字段进行函数操作、表达式操作。  尽量避免使用 like- %,在此种情况下可以进行全文检索。  原文:https://blog.csdn.net/qq_40026782/article/details/96429076?spm=1001.2014.3001.5502 
  • [其他] Mybatis+mysql批量插入性能分析测试
     环境说明 项目使用springboot mybatis 数据库mysql5.7 使用本地mysql所以网络可以忽略不计 插入对象完全相同,只有id自增  表结构如下: CREATE TABLE order_test_tab ( id int(11) NOT NULL AUTO_INCREMENT COMMENT 'id', order_id varchar(20) NOT NULL COMMENT '订单号', order_name varchar(100) NOT NULL COMMENT '订单名称', order_status int(1) NOT NULL COMMENT '订单状态', order_content varchar(255) NOT NULL COMMENT '订单说明', add_time datetime NOT NULL COMMENT '订单时间', PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试订单表';    方法说明 我使用了和文章中提到的一样,三种方法进行测试  方法一: 使用for循环调用单条插入    方法二: 在sql中使用foreach进行批量insert   方法三: 使用mybatis的批量插入     结果说明 插入条数    100    500    1000    5000    100000 使用for循环插入    139ms    545ms    839ms    2629ms    31157ms 使用sql foreach插入    55ms    119ms    123ms    329ms    报错 使用批量执行插入    48ms    111ms    239ms    1081ms    19235ms 其中报错是因为sql长度过长超过了max_allowed_packet导致的,报错信息如下: Error updating database. Cause: com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (22,700,108 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.  从结果我们显然可以看出,使用第二种方式(使用sql foreach插入)效率最高,明显与文章中差距很大,所以mysql和sqlserver还是有很大区别的,估计mysql针对批量插入的语句有过优化    测试说明 1.测试具体插入之前,首先执行删除表中所有数据操作,一个是保证环境完全一致,一个是为了减少第一次连接数据库所带来的性能消耗。 2.执行时间的计算就是在执行sql的前后,创建对象的时间不计算在这之内 3.在使用本地mysql测试完成之后,使用外网服务器的mysql进行测试,测试结果基本一致,时间都略有延长  4.测试代码在:https://github.com/LinkinStars/springBootTemplate/tree/test-batch-insert 其中包含order字样的为测试相关代码,别的是无关代码,入口在test包下的OrderTest.java    结论 批量插入时还是使用sql foreach插入来的效率最高,因为它是整一条sql在执行所以当插入条数很多的时候会出现异常,所以使用这种方式时一定要主动限制插入的最大条数,不然容易出现异常,因为max_allowed_packet即使再大也会有不够用的时候。 同时我们也应该竟可能去避免使用for循环插入数据,因为性能真的很差   原文https://blog.csdn.net/qq_40026782/article/details/98057116?spm=1001.2014.3001.5502 
  • [其他] mysql 间隙锁
     环境:mysql5.6  innodb存储引擎,默认隔离级别repeatable-read,可重复读。innodb_locks_unsafe_for_binlog, 参数默认值是OFF,也就是启用间隙锁, 他是一个bool值, 当值为true时表示disable间隙锁  知识:与oracle不同的是,mysql加锁是对索引加锁  在进行删除或者修改操作时,如果过滤条件列是非唯一索引,为了保证当前读的数据一致性,mysql通过间隙锁对数据之间区域进行锁定。(实际上是通过锁定索引达到效果)  这种锁叫间隙锁,这种锁定会造成许多误杀,很多并不冲突的数据会因为间隙锁而无法插入。     举例:  准备测试数据  create table test (id int,name varchar(10)); alter table test add primary key PK_ID (id); alter table test add index INX_Name (name); insert into test values (1,'a1'); insert into test values (2,'a1'); insert into test values (3,'a1'); insert into test values (4,'a3'); insert into test values (5,'a4'); insert into test values (11,'a6'); insert into test values (21,'a10'); insert into test values (22,'a13'); insert into test values (23,'a14'); insert into test values (24,'a15');  session one;          删除name='a3',因为间隙锁的缘故,会对 (24,a15)和(4,a3)之间加锁,(4,a3)和(5,a4)之间加锁。  很明显,如果我们想插入a2到name字段中,必然会因为间隙锁,而处于等待状态。     测试:session two      insert into test(id,name) values (30,'a2'); 插入等待,并且锁等待超时。      同样a3,a4之间插入数据也会处于等待超时。     这时很容易想到一个问题,如果间隙锁是在两组数据中间加锁,那么如果我插入a3两边的数据,a15或者a4,是否会出现锁等待呢。  继续做测试:   继续插入:insert into test(id,name) values(20,'a15');                   insert into test(id,name) values(26,'a15');  可以看到插入ID 20很快成功,插入ID 26 出现锁等待。  同样是a15,因为ID不同,结果不一样,是什么原因呢。  我们来看插入后的一个查询,很容易就理解了:   这个查询是按照name列的索引做的顺序排序,我们可以看到 (20,a15)已经插入成功。  我们已经知道在(24,a15)和(4,a3)之间存在间隙锁,如果数据(26,a15)需要插入进去,那么必然会排在24 a15之后  形成:  20   a15  24   a15  26   a15  4     a3  而这样的数据必然会被间隙锁阻塞,因此导致锁等待。  所以我们在上面明确间隙锁的时候,需要书写一组数据(主键列,辅助索引列),而不是单单只写一列。     最后得出结论:  间隙锁锁定了辅助索引两个叶子节点之间的内容,会造成锁定多余区域的数据。  先delete再insert的操作时常会导致死锁情况的出现。  应用程序sql中,在做删除或者更新操作中,对于过滤条件尽量选择主键列或者唯一索引列 ————————————————                              版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。                          原文链接:https://blog.csdn.net/qq_40026782/article/details/98074742 
  • [其他] InnoDB的行记录格式, Compact, Redundant, Compressed, Dynamic
     InnoDB存储引擎和大多数数据库一样(如Oracle和Microsoft SQL Server数据库),记录是以行的形式存储的。这意味着页中保存着表中一行行的数据。到MySQL 5.1时,InnoDB存储引擎提供了Compact和Redundant两种格式来存放行记录数据,Redundant是为兼容之前版本而保留的,如果你阅读过InnoDB的源代码,会发现源代码中是用PHYSICAL RECORD(NEW STYLE)和PHYSICAL RECORD(OLD STYLE)来区分两种格式的。MySQL 5.1默认保存为Compact行格式。你可以通过命令SHOW TABLE STATUS LIKE 'table_name'来查看当前表使用的行格式,其中row_format就代表了当前使用的行记录结构类型。例如:  use mysql;  show table status like 'user'\G   数据库实例的一个作用就是读取页中存放的行记录。如果我们知道规则,那么也可以读取其中的记录,如之前的py_innodb_page_info工具。下面将具体分析各格式存放数据的规则。  回到顶部  Compact行记录格式 Compact行记录是在MySQL 5.0时被引入的,其设计目标是能高效存放数据。简单来说,如果一个页中存放的行数据越多,其性能就越高。Compact行记录以如下方式进行存储:    Compact行格式的首部是一个非NULL变长字段长度列表,而且是按照列的顺序逆序放置的。当列的长度小于255字节,用1字节表示,若大于255个字节,用2个字节表示,变长字段的长度最大不可以超过2个字节(这也很好地解释了为什么MySQL中varchar的最大长度为65 535,因为2个字节为16位,即216=1=65 535)。第二个部分是NULL标志位,该位指示了该行数据中是否有NULL值,用1表示。该部分所占的字节应该为bytes。接下去的部分是为记录头信息(record header),固定占用5个字节(40位),每位的含义见下表4-1。最后的部分就是实际存储的每个列的数据了,需要特别注意的是,NULL不占该部分任何数据,即NULL除了占有NULL标志位,实际存储不占有任何空间。另外有一点需要注意的是,每行数据除了用户定义的列外,还有两个隐藏列,事务ID列和回滚指针列,分别为6个字节和7个字节的大小。若InnoDB表没有定义Primary Key,每行还会增加一个6字节的RowID列。   下面用一个具体事例来分析Compact行记录的内部结构:  create table mytest (    t1 varchar(10),    t2 varchar(10),    t3 char(10),    t4 varchar(10)  ) engine=innodb charset=latin1 row_format=compact;  insert into mytest values('a','bb','bb','ccc');   insert into mytest values('d','ee','ee','fff');   insert into mytest values('d',NULL,NULL,'fff');   select * from mytest\G;   创建了mytest表,有4个列,t1、t2、t4都为varchar变长字段类型,t3为固定长度类型char。接着我们插入了3条有代表性的数据,接着打开mytest.ibd(启用了innodb_file_per_table,若你没有启用该选项,请打开默认的共享表空间文件ibdata1)。在Windows下,可以选择用UltraEdit打开该二进制文件(在Linux环境下,使用hexdump -C -v mytest.ibd>mytest.txt即可),打开mytest.txt文件,找到如下内容:   0000c070 73 75 70 72 65 6d 75 6d 03 02 01 00 00 00 10 00|supremum…… 0000c080 2c 00 00 00 2b 68 00 00 00 00 00 06 05 80 00 00|,……+h…… 0000c090 00 32 01 10 61 62 62 62 62 20 20 20 20 20 20 20|.2..abbbb 0000c0a0 20 63 63 63 03 02 01 00 00 00 18 00 2b 00 00 00|ccc……+…… 0000c0b0 2b 68 01 00 00 00 00 06 06 80 00 00 00 32 01 10|+h……2.. 0000c0c0 64 65 65 65 65 20 20 20 20 20 20 20 20 66 66 66|deeeefff 0000c0d0 03 01 06 00 00 20 ff 98 00 00 00 2b 68 02 00 00|……+h…… 0000c0e0 00 00 06 07 80 00 00 00 32 01 10 64 66 66 66 00|……2..dfff. 该行记录从0000c078开始,若整理如下,相信你会有更好的理解: 03 02 01/*变长字段长度列表,逆序*/ 00/*NULL标志位,第一行没有NULL值*/ 00 00 10 00 2c/*记录头信息,固定5字节长度*/ 00 00 00 2b 68 00/*RowID我们建的表没有主键,因此会有RowID*/ 00 00 00 00 06 05/*TransactionID*/ 80 00 00 00 32 01 10/*Roll Pointer*/ 61/*列1数据'a'*/ 62 62/*列2'bb'*/ 62 62 20 20 20 20 20 20 20 20/*列3数据'bb'*/ 63 63 63/*列4数据'ccc'*/ 现在第一行数据就展现在我们眼前了。需要注意的是,变长字段长度列表是逆序存放的,03 02 01,而不是01 02 03。还需要注意的是InnoDB每行有隐藏列。同时可以看到,固定长度char字段在未填充满其长度时,会用0x20来进行填充。再来分析一下,记录头信息的最后4个字节代表next_recorder,0x6800代表下一个记录的偏移量,当前记录的位置+0x6800就是下一条记录的起始位置。所以InnoDB存储引擎在页内部是通过一种链表的结构来串联各个行记录的。  第二行我将不做整理,除了RowID不同外,它和第一行大同小异,有兴趣的读者可以用上面的方法自己试试。  现在我们关注有NULL值的第三行:  03 01/*变长字段长度列表,逆序*/  06/*NULL标志位,第三行有NULL值*/  00 00 20 ff 98/*记录头信息*/  00 00 00 2b 68 02/*RowID*/  00 00 00 00 06 07/*TransactionID*/  80 00 00 00 32 01 10/*Roll Pointer*/  64/*列1数据'd'*/  66 66 66/*列4数据'fff'*/  第三行有NULL值,因此NULL标志位不再是00而是06了,转换成二进制为00000110,为1的值即代表了第2列和第3列的数据为NULL,在其后存储列数据的部分,我们会发现没有存储NULL,只存储了第1列和第4列非NULL的值。这个例子很好地说明了:不管是char还是varchar类型,NULL值是不占用存储空间的。  回到顶部  Redundant行记录格式 Redundant是MySQL 5.0版本之前InnoDB的行记录存储方式,MySQL 5.0支持Redundant是为了向前兼容性。Redundant行记录以如下方式存储:   从上图可以看到,不同于Compact行记录格式,Redundant行格式的首部是一个字段长度偏移列表,同样是按照列的顺序逆序放置的。当列的长度小于255字节,用1字节表示;若大于255个字节,用2个字节表示。第二个部分为记录头信息(record header),不同于Compact行格式,Redundant行格式固定占用6个字节(48位),每位的含义见表4-2。从表中可以看到,n_fields值代表一行中列的数量,占用10位,这也很好地解释了为什么MySQL一个行支持最多的列为1023。另一个需要注意的值为1byte_offs_flags,该值定义了偏移列表占用1个字节还是2个字节。最后的部分就是实际存储的每个列的数据了。   创建一张和mytest内容完全一样、但行格式为Redundant的表mytest2  create table mytest2 engine=innodb row_format=redundant as (select * from mytest);  show table status like 'mytest2'\G  select * from mytest2\G  现在row_format变为Redundant。同样,通过hexdump将表空间mytest2.ibd导出到文本文件mytest2.txt。打开文件,找到类似如下行:  0000c070 08 03 00 00 73 75 70 72 65 6d 75 6d 00 23 20 16|……supremum.#. 0000c080 14 13 0c 06 00 00 10 0f 00 ba 00 00 00 2b 68 0b|……+h. 0000c090 00 00 00 00 06 53 80 00 00 00 32 01 10 61 62 62|……S……2..abb 0000c0a0 62 62 20 20 20 20 20 20 20 20 63 63 63 23 20 16|bb ccc#. 0000c0b0 14 13 0c 06 00 00 18 0f 00 ea 00 00 00 2b 68 0c|……+h. 0000c0c0 00 00 00 00 06 53 80 00 00 00 32 01 1e 64 65 65|……S……2..dee 0000c0d0 65 65 20 20 20 20 20 20 20 20 66 66 66 21 9e 94|ee fff!.. 0000c0e0 14 13 0c 06 00 00 20 0f 00 74 00 00 00 2b 68 0d|……t……+h. 0000c0f0 00 00 00 00 06 53 80 00 00 00 32 01 2c 64 00 00|……S……2.,d.. 0000c100 00 00 00 00 00 00 00 00 66 66 66 00 00 00 00 00|……fff……  整理可以得到如下内容: 23 20 16 14 13 0c 06/*长度偏移列表,逆序*/ 00 00 10 0f 00 ba/*记录头信息,固定6个字节*/ 00 00 00 2b 68 0b/*RowID*/ 00 00 00 00 06 53/*TransactionID*/ 80 00 00 00 32 01 10/*Roll Point*/ 61/*列1数据'a'*/ 62 62/*列2数据'bb'*/ 62 62 20 20 20 20 20 20 20 20/*列3数据'bb'Char类型*/ 63 63 63/*列4数据'ccc'*/ 23 20 16 14 13 0c 06,逆转为06,0c,13,14,16,20,23。分别代表第一列长度6,第二列长度6(6+6=0x0C),第三列长度为7(6+6+7=0x13),第四列长度1(6+6+7+1=0x14),第五列长度2(6+6+7+1+2=0x16),第六列长度10(6+6+7+1+2+10=0x20),第七列长度3(6+6+7+1+2+10+3=0x23)。  记录头信息中应该注意48位中22~32位,为0000000111,表示表共有7个列(包含了隐藏的3列),接下去的33位为1,代表偏移列表为一个字节。  后面的信息就是实际每行存放的数据了,这与Compact行格式大致相同。  请注意是大致相同,因为如果我们来看第三行,会发现对于NULL的处理两者是不同的。  21 9e 94 14 13 0c 06/*长度偏移列表,逆序*/  00 00 20 0f 00 74/*记录头信息,固定6个字节*/  00 00 00 2b 68 0d/*RowID*/  00 00 00 00 06 53/*TransactionID*/  80 00 00 00 32 01 10/*Roll Point*/  64/*列1数据'a'*/  00 00 00 00 00 00 00 00 00 00/*列3数据NULL*/  66 66 66/*列4数据'fff'*/  这里与之前Compact行格式有着很大的不同了,首先来看长度偏移列表,我们逆序排列后得到06 0c 13 14 94 9e 21,前4个值都很好理解,第5个NULL变为了94,接着第6个列char类型的NULL值为9e(94+10=0x9e),之后的21代表14+3=0x21。可以看到对于varchar的NULL值,Redundant行格式同样不占用任何存储空间,因而char类型的NULL值需要占用空间。  当前表mytest2的字符集为Latin1,每个字符最多只占用1个字节。若这里将表mytest2的字符集转换为utf8,第三列char固定长度类型就不再是只占用10个字节了,而是10×3=30个字节,Redundant行格式下char固定字符类型将会占据可能存放的最大值字节数。  回到顶部  Compressed与Dynamic行记录格式 InnoDB Plugin引入了新的文件格式(file format,可以理解为新的页格式),对于以前支持的Compact和Redundant格式将其称为Antelope文件格式,新的文件格式称为Barracuda。Barracuda文件格式下拥有两种新的行记录格式Compressed和Dynamic两种。新的两种格式对于存放BLOB的数据采用了完全的行溢出的方式,在数据页中只存放20个字节的指针,实际的数据都存放在BLOB Page中,而之前的Compact和Redundant两种格式会存放768个前缀字节。  下图是Barracuda文件格式的溢出行:   Compressed行记录格式的另一个功能就是,存储在其中的行数据会以zlib的算法进行压缩,因此对于BLOB、TEXT、VARCHAR这类大长度类型的数据能进行非常有效的存储。   原文:https://blog.csdn.net/qq_40026782/article/details/99544653?spm=1001.2014.3001.5502 
  • [其他] MySQL查询锁表语句详情
     1、查询是否锁表  show OPEN TABLES where In_use > 0;  查询到相对应的进程 === 然后 kill    id  2、查询进程      show processlist     补充:  查看正在锁的事务  SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;      查看等待锁的事务  SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;         -- 查出死锁进程:SHOW PROCESSLIST  -- 杀掉进程          KILL 420821;  其它关于查看死锁的命令:  1:查看当前的事务 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;  2:查看当前锁定的事务  SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;  3:查看当前等锁的事务 SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;  -- 查询死锁详情  SELECT r.trx_id waiting_trx_id,r.trx_mysql_thread_id waiting_thread, TIMESTAMPADD(SECOND,r.trx_wait_started,CURRENT_TIMESTAMP) wait_time, r.trx_query waiting_query, l.lock_table waiting_table_lock, b.trx_id blocking_trx_id,b.trx_mysql_thread_id blocking_thread, SUBSTRING(p.`HOST`,1,INSTR(p.`HOST`,':')-1) blocking_host, SUBSTRING(p.`HOST`,INSTR(p.`HOST`,':')+1) blocking_port, IF(p.COMMAND ='Sleep',p.TIME,0) idle_in_trx, b.trx_query blocking_query from information_schema.INNODB_LOCK_WAITS w INNER JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_lock_id INNER JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id INNER JOIN information_schema.INNODB_LOCKS l ON l.lock_id = w.requested_lock_id LEFT JOIN information_schema.`PROCESSLIST` p ON p.id = b.trx_mysql_thread_id ORDER BY wait_time desc;        1 show processlist;    SHOW PROCESSLIST显示哪些线程正在运行。您也可以使用mysqladmin processlist语句得到此信息。如果您有SUPER权限,您可以看到所有线程。否则,您只能看到您自己的线程(也就是,与您正在使用的MySQL账户相关的线程)。如果有线程在update或者insert 某个表,此时进程的status为updating 或者 sending data。     如果您得到“too many connections”错误信息,并且想要了解正在发生的情况,本语句是非常有用的。MySQL保留一个额外的连接,让拥有SUPER权限的账户使用,以确保管理员能够随时连接和检查系统(假设您没有把此权限给予所有的用户)。     Status  含义  Checking table  正在检查数据表(这是自动的)。  Closing tables  正在将表中修改的数据刷新到磁盘中,同时正在关闭已经用完的表。这是一个很快的操作,如果不是这样的话,就应该确认磁盘空间是否已经满了或者磁盘是否正处于重负中。  Connect Out  复制从服务器正在连接主服务器。  Copying to tmp table on disk  由于临时结果集大于tmp_table_size,正在将临时表从内存存储转为磁盘存储以此节省内存。  Creating tmp table  正在创建临时表以存放部分查询结果。  deleting from main table  服务器正在执行多表删除中的第一部分,刚删除第一个表。  deleting from reference tables  服务器正在执行多表删除中的第二部分,正在删除其他表的记录。  Flushing tables  正在执行FLUSH TABLES,等待其他线程关闭数据表。  Killed  发送了一个kill请求给某线程,那么这个线程将会检查kill标志位,同时会放弃下一个kill请求。MySQL会在每次的主循环中检查kill标志位,不过有些情况下该线程可能会过一小段才能死掉。如果该线程程被其他线程锁住了,那么kill请求会在锁释放时马上生效。  Locked  被其他查询锁住了。  Sending data  正在处理SELECT查询的记录,同时正在把结果发送给客户端。  Sorting for group  正在为GROUP BY做排序。  Sorting for order  正在为ORDER BY做排序。  Opening tables  这个过程应该会很快,除非受到其他因素的干扰。例如,在执ALTER TABLE或LOCK TABLE语句行完以前,数据表无法被其他线程打开。正尝试打开一个表。  Removing duplicates  正在执行一个SELECT DISTINCT方式的查询,但是MySQL无法在前一个阶段优化掉那些重复的记录。因此,MySQL需要再次去掉重复的记录,然后再把结果发送给客户端。  Reopen table  获得了对一个表的锁,但是必须在表结构修改之后才能获得这个锁。已经释放锁,关闭数据表,正尝试重新打开数据表。  Repair by sorting  修复指令正在排序以创建索引。  Repair with keycache  修复指令正在利用索引缓存一个一个地创建新索引。它会比Repair by sorting慢些。  Searching rows for update  正在讲符合条件的记录找出来以备更新。它必须在UPDATE要修改相关的记录之前就完成了。  Sleeping  正在等待客户端发送新请求。  System lock  正在等待取得一个外部的系统锁。如果当前没有运行多个mysqld服务器同时请求同一个表,那么可以通过增加--skip-external-locking参数来禁止外部系统锁。  Upgrading lock  INSERT DELAYED正在尝试取得一个锁表以插入新记录。  Updating  正在搜索匹配的记录,并且修改它们。  User Lock  正在等待GET_LOCK()。  Waiting for tables  该线程得到通知,数据表结构已经被修改了,需要重新打开数据表以取得新的结构。然后,为了能的重新打开数据表,必须等到所有其他线程关闭这个表。以下几种情况下会产生这个通知:FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE,或OPTIMIZE TABLE。  waiting for handler insert  INSERT DELAYED已经处理完了所有待处理的插入操作,正在等待新的请求。     大部分状态对应很快的操作,只要有一个线程保持同一个状态好几秒钟,那么可能是有问题发生了,需要检查一下。还有其他的状态没在上面中列出来,不过它们大部分只是在查看服务器是否有存在错误是才用得着。     2 show full processlist;    show processlist;只列出前100条,如果想全列出请使用show full processlist;     3 show open tables;    这条命令能够查看当前有那些表是打开的。In_use列表示有多少线程正在使用某张表,Name_locked表示表名是否被锁,这一般发生在Drop或Rename命令操作这张表时。所以这条命令不能帮助解答我们常见的问题:当前某张表是否有死锁,谁拥有表上的这个锁等。     show open tables from database;         4 show status like ‘%lock%’    查看服务器状态。         5 show engine innodb statusG;    MySQL 5.1之前的命令是:show innodbstatusG;,MySQL 5.5使用上面命令即可查看innodb引擎的运行时信息。         6 show variables like ‘%timeout%’;    查看服务器配置参数。        ———————————————— 原文链接:https://blog.csdn.net/qq_40026782/article/details/100518617 
  • [其他] MySQL优化器cost计算
    记录MySQL 5.5上,优化器进行cost计算的方法。第一篇: 单表的cost计算数据结构:1. table_share: 包含了表的元数据,其中索引部分:key_info:一个key的结构体,代表一个索引,包含了:key_length:key的长度key_parts:key一共有多少个columnkey_part:key中具体的columnrec_per_key:相同的key平均有几条记录例如:123456(gdb) p (table->s->key_info->name)     $16 = 0x8ca0ffbd "PRIMARY"(gdb) p (table->s->key_info->key_parts)     $17 = 1(gdb) p (table->s->key_info->rec_per_key)     $18 = (ulong *) 0x8ca0ffe82. JOIN:    mysql_select函数中,创建了 new JOIN(thd, fields, select_options, result)对象,包含了当前查询的所有组件和各种转换结果,其中 :prepare:进行一些等价交换之类的变化optimize:选择join的方式和access pathexec:根据执行计划运行查询3. join_tab:    包含了一个table访问的cost等一些信息,经过优化后,填充这个结构体cost的计算方法cost = cpu cost + io costcpu cost:server层对返回的记录数的compare时间io cost:引擎层根据扫描记录的记录数计算cost统计信息这里用到了两部分统计信息:1. server层的统计信息,保存在table_share中。包括:key_lengthrec_per_keyblock_size等2. innodb层的统计信息,包括:stat_n_rowsstat_clustered_index_sizestat_sum_of_other_index_size主要函数调用make_join_statistics:--update_ref_and_keys: 添加可以使用的索引。--get_quick_record_count:----test_quick_select: 评估每一个join table查询得到的记录数,其中比较不同index的cost, 返回的记录数,选择最优的那个。choose plan:选择join的顺序实验过程123456789CREATE TABLE `xpchild` (  `id` int(11) NOT NULL,  `name` varchar(100) DEFAULT NULL,  `c1` int(11) DEFAULT NULL,  `c2` int(11) DEFAULT NULL,  PRIMARY KEY (`id`),  KEY `xpchild_name` (`name`),  KEY `xpchild_id_c1` (`id`,`c1`)) ENGINE=InnoDB DEFAULT CHARSET=latin1实验1: 单值查询1explain select * from xpchild where id =100;函数调用栈:make_join_statistics:    table->quick_condition_rows= table->file->stats.records;   if (s->type == JT_SYSTEM || s->type == JT_CONST)   s->found_records=s->records=s->read_time=1; s->worst_seeks=1.0;结论:单key的查询,join_tab的type=JT_CONST,索引record和read time都是1;最终得到的join->best_read=1.0;实验2: 范围查询explain select * from xpchild where id > 100;step1:update_ref_and_keys: 一共得到两个possible index,step2:test_quick_select    1. 计算全表扫描的cost:innodb全表扫描的io cost:innodb的io cost: s->read_time=(ha_rows) s->table->file->scan_time();innodb scan time:prebuilt->table->stat_clustered_index_size等于innodb这张表的聚簇索引的page个数,本身innodb就是聚簇索引表,这里计算的io cost=16(gdb) p s->read_time$7 = 16MySQL server的cpu cost:scan_time= (double) records / TIME_FOR_COMPARE + 1;(gdb) p scan_time$16 = 1359.4000000000001总的cost:read_time= (double) head->file->scan_time() + scan_time + 1.1;(gdb) p read_time$18 = 1376.5继续函数栈:根据possible index,生成sel_tree;get_best_group_min_max: 这里没有使用到get_key_scans_params:根据sel_tree找到更好的cost2. 计算full index的cost      find_shortest_key: 在覆盖索引中选择length最短的那个。      get_index_only_read_time:这里如果有覆盖索引(covering index)那么就会计算此覆盖索引的cost。      full index scan的计算方法:1234uint keys_per_block= (param->table->file->stats.block_size/2/                      (param->table->key_info[keynr].key_length+                       param->table->file->ref_length) + 1);read_time=((double) (records+keys_per_block-1)/(double) keys_per_block);     这里假设:一个块中,只使用了一半的空间写入数据,     如果计算的key_read_time > read_time, 则read_time= key_read_time,从此不再使用全表扫描。3. pk 索引计算的cost进入get_key_scans_params函数:选择比传入的read_time小的cost的执行计划,生成一个TRP_RANGE对象返回。step1: 评估范围扫描的记录数(check_quick_select)check_quick_keys:根据key,min,max值来评估记录数,并把records记录到table->quick_rows[key]中,以便后续需要。12(gdb) p *min_key$82 = 100 'd'ha_innobase::records_in_range: innodb引擎根据min和max值来评估记录数。    计算方法:innodb对b_tree中范围确定的page的个数和record_per_page进行计算,当评估>all_record/2时,就取all_record/2。12(gdb) p records$112 = 3396step 2: 计算cost根据pk range估算的records=3396,调整table->quick_condition_rows从全表的6792到现在的3396。计算cost:12345cpu_cost= (double) found_records / TIME_FOR_COMPARE;cpu_cost= 679.20000000000005<br>io_cost = param->table->file->read_time(keynr,param->range_count,found_records);<br>found_read_time = cpu_cost + io_cost + 0.01found_read_time = 683.74750000000006这样,通过pk扫描的cost远小于前面第一阶段的全表扫描的代价。4. 计算普通索引的cost     因为都可以使用前导列进行查询,查询的效率的差别在于非主键索引需要回到聚簇索引中查询非索引列。所以,innodb返回的found_rows=6556(包含了扫描索引xpchild_id_c1 和primary key的), 所以最终计算的cost大于使用pk的cost。      最终计算得到的cost=7868.21 远高于pk索引的cost。结论: 最终选择了pk的索引进行range扫描原文:https://blog.csdn.net/qq_40026782/article/details/105773496?spm=1001.2014.3001.5502
  • [其他] mysql 常用查询语句
     1、查询一张表的详细信息(包括字段注释,字段名称,类型等).  select * from information_schema.columns where table_schema ='my_db'  and table_name = 'auth_user';     2、Mysql是否开启binlog:show variables like 'log_bin';  3、查看日志:show variables like 'log_%';  4、mysql删除日志(解决阿里云RDS日志无法删除问题)不太建议使用,但是阿里云不给删日志,空间占用太多了,所以就直接删了:  RESET MASTER;//删除所有binlog日志,新日志编号从头开始  如果可以权限比较充足,建议使用下面删除语句:   purge binary logs to 'mysql-bin.000079';   show binary logs;  Mysql中如何查看慢查询以及查看线程  SELECT * , CONVERT(sql_text USING utf8)  AS userNam    FROM  mysql.slow_log where  start_time > '2019-11-05 10'    -- and query_time >'00:01:00.000000'  ORDER BY query_time DESC ;    查看表是否被锁: 直接在mysql命令行执行:show engine innodb status\G。 查看造成死锁的sql语句,分析索引情况,然后优化sql. 然后show processlist,查看造成死锁占用时间长的sql语句。 show status like ‘%lock%。   查看表被锁状态和结束死锁步骤: 1.查看表被锁状态 show OPEN TABLES where In_use > 0; 这个语句记录当前锁表状态  2.查询进程 show processlist 查询表被锁进程 查询到相应进程kill id 3.分析锁表的SQL 分析相应SQL,给表加索引,常用字段加索引,表关联字段加索引   查看正在锁的事物: SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS. 查看等待锁的事物: SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS.  ————————————————  原文链接:https://blog.csdn.net/qq_40026782/article/details/93622577 
  • [其他] mysql中有少量数据的表是否要加索引
    例如对于只有100条数据的MySQL表是否有必要加索引,这取决于具体的使用场景。以下是一些考虑因素:查询频率:如果该字段是查询条件中经常使用的,且查询频率较高,那么加索引可以提高查询效率。数据唯一性:如果该字段的值具有较高唯一性,即不同值的数量接近于表中记录的数量,那么索引的选择性会很高,加索引会更加有效。查询优化:如果您的查询可以通过索引覆盖来避免访问原始数据,那么即使是小表,加索引也是有益的。维护成本:虽然索引可以提高查询性能,但它也会增加数据插入、更新和删除时的维护成本。因此,如果表数据量不大,且更新频繁,可能不需要加索引。总的来说,如果该字段是查询条件中经常使用的、数据唯一性高、查询优化明显,并且维护成本不是问题,那么加索引是有必要的。反之,如果这个字段很少作为查询条件,或者数据唯一性不高,那么加索引可能收益不大。在实际操作中,建议根据具体的业务需求和数据库使用情况来决定是否加索引。
总条数:1412 到第 页
上滑加载中