这篇文章,理论上不是很难,MySQL是一个大块,这种零散的认识方式,终究需要一个系统的学习串起来。 转自 前言 大家都知道 MySQL 的数据都是保存在磁盘的,那具体是保存在哪个文件呢?MySQL 存储的行为是由存储引擎实现的,MySQL 支持多种存储引擎,不同的存储引擎保存的文件自然也不同。InnoDB 是我们常用的存储引擎,也是 MySQL 默认的存储引擎。本文主要以 InnoDB 存储引擎展开讨论。 InnoDB简介 InnoDB是一个将表中的数据存储到磁盘上的存储引擎。而真正处理数据的过程是发生在内存中的,所以需要把磁盘中的数据加载到内存中,如果是处理写入或修改请求的话,还需要把内存中的内容刷新到磁盘上。而我们知道读写磁盘的速度非常慢,和内存读写差了几个数量级。所以当我们想从表中获取某些记录时,InnoDB存储引擎需要一条一条的把记录从磁盘上读出来么?想要了解这个问题,我们首先需要了解InnoDB的存储结构是怎样的。 InnoDB采取的方式是:将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位innodb_page_size选项指定了MySQL实例的所有InnoDB表空间的页面大小。这个值是在创建实例时设置的,之后保持不变。有效值为64KB,32KB,16KB(默认值 ),8kB和4kB。也就是在一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。 InnoDB行格式 我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为行格式或者记录格式。一行记录可以以不同的格式存在InnoDB中,行格式分别是compact、redundant、dynamic和compressed行格式。可以在创建或修改的语句中指定行格式: mysql5.0之前默认的行格式是redundant,mysql5.0之后的默认行格式为compact , 5.7之后的默认行格式为dynamic compact格式 记录的额外信息 记录的额外信息:分别是变长字段长度列表、NULL值列表和记录头信息 1:变长字段长度列表 mysql中支持一些变长数据类型(比如VARCHAR(M)、TEXT等),它们存储数据占用的存储空间不是固定的,而是会随着存储内容的变化而变化。在Compact行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长字段长度列表,各变长字段数据占用的字节数按照列的顺序逆序存放 2:NULL值列表 NULL值列表:Compact格式会把所有可以为NULL的列统一管理起来,存在一个NULL值列表,如果表中没有允许为NULL的列,则NULL值列表也不复存在了。 为什么要有NULL值列表? 表中的某些列可能存储NULL值,如果把这些NULL值都放到记录的真实数据中存储会很浪费空间,所以Compact行格式把这些值为NULL的列统一管理起来,存储到NULL值列表中,它的处理过程是这样的: 3:记录头信息 名称 大小(单位:bit) 描述 预留位1 1 未使用 预留位2 1 未使用 delete_mask 1 标记改记录是否被删除 min_rec_mask 1 B+树非叶子节点中最小记录都会添加该标记 n_owned 4 当前记录拥有的记录数 heap_no 13 当前记录在记录堆的位置信息 record_type 3 […]
转自 关于MySQL中的行锁、间隙锁这些之前一直不清楚,这篇文章讲的还是比较清晰的 这篇文章就来详细总结下 InnoDB 存储引擎中的行锁的加锁规则,并辅以实例解释。 首先众所周知,InnoDB 三种行锁: 哪些语句上面会加行锁? 1)对于常见的 DML 语句(如 UPDATE、DELETE 和 INSERT ),InnoDB 会自动给相应的记录行加写锁 2)默认情况下对于普通 SELECT 语句,InnoDB 不会加任何锁,但是在 Serializable 隔离级别下会加行级读锁 上面两种是隐式锁定,InnoDB 也支持通过特定的语句进行显式锁定: 3)SELECT * FROM table_name WHERE … FOR UPDATE,加行级写锁 4)SELECT * FROM table_name WHERE … LOCK IN SHARE MODE,加行级读锁 前置知识就不过多介绍了,在学习具体行锁加锁规则之前,小伙伴们需要记住加锁规则的两条核心: 1)查找过程中访问到的对象才会加锁 这句话该怎么理解?比如有主键 id 为 1 2 3 4 5 … 10 的 […]
转自 这篇文章还不错,尤其是三大日志那里,虽然不复杂,但讲的很明白了 学一个技术,我们先要 跳出来,看整体,先要在脑中有一个这个技术的全貌。然后再 钻进去,看本质,深入的研究细节。这样方便我们建立一个立体的知识网络。不然单学多个知识点,是串不起来的。不容易记住,理解也不会深刻。 所以,我们先把 MySQL 拆解一下,看看内部有哪些组件,我们 Java系统执行一条SQL,MySQL的内部是如何运作,给我们返回结果的。 我们先从我们访问数据库说起 – 我们想要查询数据库,首先得建立网络连接 MySQL 驱动负责建立网络连接,然后请求 MySQL 数据库 其实就是创建了一个数据库连接 Java系统的 数据库连接池 – 如果我们的系统所有线程访问数据库时,都使用一个连接会怎样 – 所有线程抢夺一个连接,没有连接 就操作不了数据库,效率极低,因为需要后面的线程需要等待前面的线程处理完才行 – 我们的系统如果每个线程访问数据库时,都创建一个连接,然后销毁,会怎样 – 创建连接需要网络通信,网络通信是很耗时的 好不容易创建了连接,查询完就给销毁了,那效率肯定低 – 所以,我们要使用数据库连接池 – 数据库连接池里,会有多个数据库连接 每个线程使用完连接后,会放回池子,连接不会销毁 常用的数据库连接池有 DBCP、C3P0、Druid MySQL 的 连接器 – Java 系统要和MySQL 建立多个连接,那 MySQL 自然也需要维护与系统之间的连接 所以,MySQL 整体架构的第一个组件就是 连接器 MySQL 连接器的功能 […]
执行顺序 (7) SELECT (8) DISTINCT <select_list> (1) FROM <left_table> // 这里FROM不止处理后面这一张,包括JOIN 中的,一起处理,笛卡尔积。 (3) <join_type> JOIN <right_table> // 这里指的是根据JOIN的方式,确定保留的内容。 (2) ON <join_condition> // 先ON 再 JOIN逻辑。 (4) WHERE <where_condition> // 先WHERE条件过滤、再GROUP BY分组、再HAVING过滤、再DISTINCT排重、再ORDER BY排序、最后LIMIT。 (5) GROUP BY <group_by_list> (6) HAVING <having_condition> (9) ORDER BY <order_by_condition> (10) LIMIT <limit_number> 连接器:认证、授权 查询缓存(8.0移除) 分析器:词法分析、语法分析 优化器:连接优化、索引选取 执行器:访问权限、引擎API调用
转:https://www.xttblog.com/?p=4926 背景 MySQL/InnoDB的加锁分析,一直是一个比较困难的话题。我在工作过程中,经常会有同事咨询这方面的问题。同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题。本文,准备就MySQL/InnoDB的加锁问题,展开较为深入的分析与讨论,主要是介绍一种思路,运用此思路,拿到任何一条SQL语句,都能完整的分析出这条语句会加什么锁?会有什么样的使用风险?甚至是分析线上的一个死锁场景,了解死锁产生的原因。 注:MySQL是一个支持插件式存储引擎的数据库系统。本文下面的所有介绍,都是基于InnoDB存储引擎,其他引擎的表现,会有较大的区别。 多版本并发控制 MVCC MySQL InnoDB 存储引擎,实现的是基于多版本的并发控制协议 MVCC (Multi-Version Concurrency Control) ,与 MVCC 相对的,是基于锁的并发控制,Lock-Based Concurrency Control。MVCC 最大的好处,相信也是耳熟能详:读不加锁,读写不冲突。在读多写少的 OLTP 应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,这也是为什么现阶段,几乎所有的 RDBMS,都支持了 MVCC。 在 MVCC 并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。 在一个支持 MVCC 并发控制的系统中,哪些读操作是快照读?哪些操作又是当前读呢?以 MySQL InnoDB 为例,看下面的例子: 快照读:简单的select操作,属于快照读,不加锁。(当然,也有例外,下面会分析) 当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。 select * from table where ? lock in share mode; select * […]
大约在两个月前,有同事在使用 Select 查询语句的时候,发现整张表被锁了,导致日志中经常出现 time out 异常。当时我判断是 select 不可能锁表的,而且更不可能锁整张表。直到今天我抽出时间查询资料,才发现不仅 Select 会锁整张表,Update 和 delete 都会锁整张表,这里面的原因且听本文分解! InnoDB 的细粒度行锁以及事务支持一度是 MySQL 最吸引人的特性之二。但是在多种情况下,InnoDB 的行级锁会变成表级锁。使用不当,给我们带来的危害极大! 如果 InnoDB 的查询没有命中索引,也将退化为表锁。InnoDB 的细粒度锁,是实现在索引记录上的。 InnoDB 的索引 InnoDB 的索引有两类。聚集索引(Clustered Index)与普通索引(Secondary Index)。 InnoDB 的每一个表都会有聚集索引。如果你没手动创建,InnoDB 也会默认的帮你创建聚集索引。 聚集索引以下面三种形式存在: 如果表定义了 PK,则 PK 就是聚集索引; 如果表没有定义 PK,则第一个非空 unique 列是聚集索引; 否则,InnoDB 会创建一个隐藏的 row-id 作为聚集索引。 我们知道索引的结构是 B+ 树,这里不展开 B+ 树的细节,先说几个结论: 在索引结构中,非叶子节点存储 key,叶子节点存储 value; 聚集索引,叶子节点存储行记录(row); 普通索引,叶子节点存储了 […]
90% 的程序员都认为 innodb 是行级锁,但实际上使用不当,它也是表级锁! 最近生产上的 MySQL 数据库,是不是的就来一次 DeadLock,其中我做了故障排查,昨天做了相关的升级,导致昨天非常的忙,很多网友加我好友,都没有及时回应,直到晚上升级结束,我在群里做了相关的解释! 截了一段错误日志信息如下: 21:02:02.563 ERROR dao.CommonDao [pool-15-thread-19] [jbc.trade.xttblog.com] [703c9ddbe4b143609035365ca46bff35] – db error , tableId=jbc.trade.xttblog.com, sql=update i_pay_record set checktime = now() where order_id in (62818) , par ams=null com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction 其中涉及到的更新语句如下: update i_pay_record set checktime = now() where order_id in (62818) […]
varchar需要有一个标识长度位。所以255 + 长度位 = 256 先抛出官网答案: In contrast to CHAR, VARCHAR values are stored as a 1-byte or 2-byte length prefix plus data. The length prefix indicates the number of bytes in the value. A column uses one length byte if values require no more than 255 bytes, two length bytes if values may require […]
一、concat()函数 1、功能:将多个字符串连接成一个字符串。 2、语法:concat(str1, str2,…) 返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。 二、concat_ws()函数 1、功能:和concat()一样,将多个字符串连接成一个字符串,但是可以一次性指定分隔符~(concat_ws就是concat with separator) 2、语法:concat_ws(separator, str1, str2, …) 说明:第一个参数指定分隔符。需要注意的是分隔符不能为null,如果为null,则返回结果为null。 三、group_concat()函数 前言:在有group by的查询语句中,select指定的字段要么就包含在group by语句的后面,作为分组的依据,要么就包含在聚合函数中。 1、功能:将group by产生的同一个分组中的值连接起来,返回一个字符串结果。 2、语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator ‘分隔符’] ) 说明:通过使用distinct可以排除重复值;如果希望对结果中的值进行排序,可以使用order by子句;separator是一个字符串值,缺省为一个逗号。
NULL会导致in/not in 查询查不出结果。这一点需注意 解决方式是使用 EXISTS 代替IN 原: where xxx in () 新:where exists ()