Skip to content

Commit

Permalink
update sql docs
Browse files Browse the repository at this point in the history
  • Loading branch information
fengzhao committed Aug 6, 2024
1 parent e682340 commit 8a6822d
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 30 deletions.
21 changes: 11 additions & 10 deletions docs/basic/12.MySQL内存概述.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# 内存概述


MySQL分配缓冲区和缓存以提高数据库操作的性能。默认配置旨在允许MySQL服务器在具有大约512MB RAM的虚拟机上启动。您可以通过增加某些缓存和缓冲区相关系统变量的值来提高 MySQL 性能。您还可以修改默认配置以在内存有限的系统上运行 MySQL。
MySQL分配缓冲区和缓存以提高数据库操作的性能。默认配置旨在让`MySQL`服务器在具有大约512MB RAM的虚拟机上启动。您可以通过增加某些缓存和缓冲区相关系统变量的值来提高 `MySQL` 性能。您还可以修改默认配置以在内存有限的系统上运行 MySQL。

MySQL以两种方式使用内存
`MySQL`以两种方式使用内存

1、永久保留供其使用的内存 – 此类称为"全局缓冲区"的内存在服务器启动期间从操作系统获取,不会释放到任何其他进程。

Expand All @@ -13,11 +13,11 @@ MySQL以两种方式使用内存:



内存是重要的性能参数,常常出现由于异常的 SQL 请求以及待优化的数据库导致内存利用率升高的情况,严重时还会出现由于 OOM 导致实例发生 HA 切换的情况。
内存是重要的性能参数,常常出现由于异常的 `SQL` 请求以及待优化的数据库导致内存利用率升高的情况,严重时还会出现由于 `OOM` 导致实例发生 HA 切换的情况。

一个常见问题是实例占用大量内存或内存不足 (OOM) 问题。运行内存利用率高的数据库实例通常会导致性能问题、停滞,甚至数据库停机。

某些 MySQL 内存块在全局内使用。这意味着所有查询工作负载共享内存位置,始终被占用,并且仅在 MySQL 进程停止时释放。
某些 `MySQL` 内存块在全局内使用。这意味着所有查询工作负载共享内存位置,始终被占用,并且仅在 `MySQL` 进程停止时释放。

某些内存块基于会话,这意味着一旦会话关闭,该会话使用的内存就会释放回系统。

Expand All @@ -30,6 +30,7 @@ MySQL 的内存大体可以分为共享内存和 session 私有内存两部分

## 共享内存

MySQL 在服务器启动时分配全局缓冲区,这些缓冲区在所有连接之间共享。MySQL 的大部分内存被全局缓冲区(例如 innodb_buffer_pool_size、innodb_log_buffer_size、key_buffer_size 等)消耗了。

```SQL
mysql>
Expand Down Expand Up @@ -58,7 +59,7 @@ mysql>

- innodb_log_buffer

该部分主要存放 redo log 的信息,在 RDS 上会设置 1 M 的大小。InnoDB 会首先将 redo log 写在这里,然后按照一定频率将其刷新回重做日志文件中。该空间不需要太大,因为一般情况下该部分缓存会以较快频率刷新至 redo log(Master Thread 会每秒刷新、事务提交时会刷新、其空间少于 1/2 时同样会刷新)。
该部分主要存放 `redo log` 的信息,在 RDS 上会设置 1 M 的大小。InnoDB 会首先将 `redo log` 写在这里,然后按照一定频率将其刷新回重做日志文件中。该空间不需要太大,因为一般情况下该部分缓存会以较快频率刷新至 redo log(Master Thread 会每秒刷新、事务提交时会刷新、其空间少于 1/2 时同样会刷新)。

- innodb_additional_mem_pool

Expand All @@ -75,7 +76,7 @@ mysql>

## Session 私有内存

共享内存中介绍的内存空间是实例创建时即分配的内存空间,并且是所有连接共享的。而出现 OOM 异常的实例都是由于下面各个连接私有的内存造成的。
共享内存中介绍的内存空间是实例创建时即分配的内存空间,并且是所有连接共享的。而出现 `OOM`异常的实例都是由于下面各个连接私有的内存造成的。


```SQL
Expand Down Expand Up @@ -108,13 +109,13 @@ mysql>

分别存放了对顺序和随机扫描(例如按照排序的顺序访问)的缓存,RDS 给每个 session 设置 256 K 的大小。当 thread 进行顺序或随机扫描数据时会首先扫描该 buffer 空间以避免更多的物理读。

- sort_buffer
- sort_buffer_size

需要执行 order by 和 group by 的 SQL 都会分配 sort_buffer,用于存储排序的中间结果,在 RDS 上设置 256 K。在排序过程中,若存储量大于 sort_buffer_size,则会在磁盘生成临时表以完成操作。在 Linux 系统中,当分配空间大于 2 M 时会使用 mmap() 而不是 malloc() 来进行内存分配,导致效率降低。
`sort_buffer_size` 是一个connection级参数,在每个connection需要buffer的时候,一次性分配的内存。`sort_buffer_size`并不是越大越好,过大的设置+高并发可能会耗尽系统内存资源。需要执行 `order by``group by` 的 SQL 都会分配 `sort_buffer`,用于存储排序的中间结果,`MySQL`上默认是256 K。在排序过程中,若存储量大于`sort_buffer_size`,则会在磁盘生成临时表以完成操作。在 `Linux` 系统中,当分配空间大于 2M 时会使用 mmap() 而不是 malloc() 来进行内存分配,导致效率降低。

- join_buffer
- join_buffer_size

MySQL 仅支持 nest loop 的 join 算法,RDS 设置 256 K 的大小。处理逻辑是驱动表的一行和非驱动表联合查找,这时就可以将非驱动表放入 join_buffer,不需要访问拥有并发保护机制的 buffer_pool。
MySQL 仅支持 `nest loop` 的 join 算法,RDS 设置 256 K 的大小。处理逻辑是驱动表的一行和非驱动表联合查找,这时就可以将非驱动表放入 join_buffer,不需要访问拥有并发保护机制的 `buffer_pool`

- binlog_cache

Expand Down
13 changes: 12 additions & 1 deletion docs/basic/7.MySQL数据类型.md
Original file line number Diff line number Diff line change
Expand Up @@ -667,4 +667,15 @@ REDUNDANT format 提供了对老版本MySQL的兼容性。



## 数据类型转换
## 数据类型转换


## 自定义数据类型

用户定义数据类型并不是真正的数据类型,它只是提供了一种提高数据库内部元素和基本数据类型之间一致性的机制。


在MySQL中,数据类型用于定义列的类型和属性。MySQL提供了一些基本数据类型,如整数、字符、日期等。但在某些情况下,这些基本数据类型可能不足以满足我们的需求。

自定义数据类型允许我们创建自己的数据类型,以便更好地满足特定业务需求。通过自定义数据类型,我们可以将一组相关的数据和操作封装在一个单一的数据类型中,并将其作为列的数据类型使用。

26 changes: 15 additions & 11 deletions docs/optimize/many_tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@


## 背景

MySQL是多线程的,可能在同一时刻有很多的客户端访问某张特定的表。为了能最小化多个客户端在相同表上的不同状态问题,并发会话中访问的每张表都会单独打开。虽然这可能消耗过多的内存,但是通常会提高系统的性能。


我们知道mysql是一个支持多线程的数据库,尤其在innodb存储引擎出现后,对mysql的事务,并发,锁支持得到了极大提高。在高并发的访问的应用场景中,应用端大量并发的进程发问数据库,而数据库中的数据表在磁盘上以数据文件存放,在unix,linux的系统调用中,是依赖于文件描述符的。不同的os对文件描述符的限制不同(非Unix/linux 操作系统无文件描述符概念,在windows中称作文件句柄),如在linux中/etc/security/limits.conf配置文件中设置他们的文件描述符极限。
我们知道MySQL是一个支持多线程的数据库,尤其在innodb存储引擎出现后,对MySQL的事务,并发,锁支持得到了极大提高。

在高并发的访问的应用场景中,应用端大量并发的进程发问数据库,而数据库中的数据表在磁盘上以数据文件存放,在Unix/Linux的系统调用中,是依赖于文件描述符的。

不同的OS对文件描述符的限制不同(非Unix/Linux操作系统无文件描述符概念,在Windows中称作文件句柄),如在Linux中`/etc/security/limits.conf`配置文件中设置他们的文件描述符极限。


### 数据字典
Expand All @@ -14,11 +19,11 @@ MySQL是多线程的,可能在同一时刻有很多的客户端访问某张特

在MySQL中,数据字典信息内容就包括表结构、数据库名或表名、字段的数据类型、视图、索引、表字段信息、存储过程、触发器等内容。

`MySQL.INFORMATION_SCHEMA` 库提供了对数据局元数据、统计信息、以及有关MySQL server的访问信息(例如:数据库名或表名,字段的数据类型和访问权限等)。
`MySQL.INFORMATION_SCHEMA`库提供了对数据局元数据、统计信息、以及有关`MySQL server`的访问信息(例如:数据库名或表名,字段的数据类型和访问权限等)。

**该库中保存的信息也可以称为MySQL的数据字典。**

在MySQL8.0之前,MySQL的数据字典信息并没有全部存放在系统数据库表中,部分字典信息存放于文件中,其余的数据字典信息存放于数据字典库中(INFORMATION_SCHEMA,MYSQL,SYS)。
在MySQL8.0之前,MySQL的数据字典信息并没有全部存放在系统数据库表中,部分字典信息存放于文件中,其余的数据字典信息存放于数据字典`INFORMATION_SCHEMA`,`MySQL`,`SYS`


> 在MySQL8.0之前,如果我们使用了默认的存储引擎innodb创建一张表,那么在文件夹下面就会出现表名.frm和表名.ibd两个文件,如果我们使用的是Myisam存储引擎,那么就会出现三个文件。其中ibd文件是innodb的表数据文件,而frm文件是innodb的表结构文件,mysiam存储引擎的表中,frm是表结构,MYI文件是索引文件,而MYD文件是数据文件,从这里也可以看出,innodb存储引擎的索引和数据是在一起的,而Myisam存储引擎索引和数据是分开的。 **注意:这个frm文件和ibd文件不是文本文件,都是不能直接用编辑器打开的。** 在早期5.6版本之前,MyISAM是MySQL的默认存储引擎,而作为MyISAM存储引擎,它是没有数据字典的。只有表结构信息记录在.frm文件中。MySQL5.6版本之后,将InnoDB存储引擎作为默认的存储引擎。在InnoDB存储引擎中,添加了一些数据字典文件用于存放数据字典元信息,例如:.opt文件,记录了每个库的一些基本信息,包括库的字符集等信息,.TRN,.TRG文件用于存放触发器的信息内容。
Expand All @@ -28,7 +33,7 @@ MySQL是多线程的,可能在同一时刻有很多的客户端访问某张特

- 首先是,将所有原先存放于数据字典文件中的信息,全部存放到数据库系统表中,即将之前版本的.frm,.opt,.par,.TRN,.TRG,.isl文件都移除了,不再通过文件的方式存储数据字典信息。

- 其次是对INFORMATION_SCHEM,mysql,sys系统库中的存储引擎做了改进,原先使用MyISAM存储引擎的数据字典表都改为使用InnoDB存储引擎存放。从不支持事务的MyISAM存储引擎转变到支持事务的InnoDB存储引擎,为原子DDL的实现,提供了可能性。
- 其次是对`INFORMATION_SCHEMA`,`MySQL`,`SYS`系统库中的存储引擎做了改进,原先使用`MyISAM`存储引擎的数据字典表都改为使用`InnoDB`存储引擎存放。从不支持事务的`MyISAM`存储引擎转变到支持事务的`InnoDB`存储引擎,为原子DDL的实现,提供了可能性。


https://opensource.actionsky.com/20200709-mysql/
Expand All @@ -39,17 +44,16 @@ https://opensource.actionsky.com/20200709-mysql/

回到主题,MySQL是如何打开一个表的,InnoDB引擎的表都是以文件的形式存在磁盘中,MySQL Server要操作一个表(增删改查等),都要利用操作系统提供的文件IO接口,来操作文件。

在 Linux 中,文件IO是通过文件描述符来访问的。如果频繁的文件IO,申请和关闭文件描述符,也是有一定开销的。

`Linux` 中,文件IO是通过文件描述符来访问的。如果频繁的文件IO,申请和关闭文件描述符,也是有一定开销的。

**table cache的主要作用应该用于缓存文件描述符,当有新的请求时不需要重新的打开,使用结束时也不用立即关闭。**

**table cache的主要作用就是缓存文件描述符,当有新的请求时不需要重新打开,使用结束时也不用立即关闭。**


MySQL是一个多线程服务,所以可能存在多个线程同时访问一张表的情况。为了减少多个并发会话对同时一个表有不同状态的问题,表被每个并发会话单独打开。每个会话操作一个


当我们的数据库中上千数量的表的时候,查询中有涉及复杂的多表连接,并且同时有多个connection高并发连到mysql中执行这些query,那么就可能很快用完文件描述符cachetable_open_cache),mysql使用LRU算法,把最近最少使用的描述符关闭掉,用于存放新的描述符。
当我们的数据库中上千数量的表的时候,查询中有涉及复杂的多表连接,并且同时有多个`connection`高并发连到`MySQL`中执行这些query,那么就可能很快用完文件描述符cache`table_open_cache``MySQL`使用`LRU`算法,把最近最少使用的描述符关闭掉,用于存放新的描述符。

但是在查找要关闭的描述符中,查找时间会随着cache中的缓存数量增加而增加(O(n),n为cache的items数量),文件打开的时间等于文件关闭的时间,从而导致了性能上的下降。

Expand All @@ -61,17 +65,17 @@ MySQL是一个多线程服务,所以可能存在多个线程同时访问一张
- 参数`table_open_cache_instances`存储了表缓存实例的数量。默认值是16。它将table_open_cache分成多个实例,从而减少会话之间的竞争。


MySQL会创建16个独立的内存buffer instance,其中每个instance可以存放4000/16=250个表描述符。这些表缓存instance可以被并发访问,这样dml在使用表描述符的时候不会互相阻塞
MySQL会创建16个独立的内存`buffer instance`,其中每个`instance`可以存放4000/16=250个表描述符。这些表缓存`instance`可以被并发访问,这样`DML`在使用表描述符的时候不会互相阻塞


缓存访问在实例之间被分割开来,当有许多会话访问表时,使用缓存的操作可以获得更高的性能。(DDL 语句仍然需要对整个缓存加锁,但这种语句比 DML 语句要少得多)。


对于经常使用 16 个或更多内核的系统,建议使用 8 或 16 的值。

但是如果表中有许多大型触发器,导致内存负荷过高,那么 table_open_cache_instances 的默认设置可能会导致内存使用过多。
但是如果表中有许多大型触发器,导致内存负荷过高,那么 `table_open_cache_instances` 的默认设置可能会导致内存使用过多。

在这种情况下,将 table_open_cache_instances 设置为 1 可能会对限制内存使用有所帮助。[参考](https://www.cnblogs.com/abclife/p/15704729.html)
在这种情况下,将 `table_open_cache_instances` 设置为 1 可能会对限制内存使用有所帮助。[参考](https://www.cnblogs.com/abclife/p/15704729.html)



Expand Down
Loading

0 comments on commit 8a6822d

Please sign in to comment.