• [交流吐槽] MySQL 与 Redis 的区别
    MySQL 是持久化存储,存放在磁盘里面,检索的话,会涉及到一定的 IO,为了解决这个瓶颈,于是出现了缓存,比如现在用的最多的 memcached(简称mc)。首先,用户访问mc,如果未命中,就去访问 MySQL,之后像内存和硬盘一样,把数据复制到mc一部分。  Redis 和mc都是缓存,并且都是驻留在内存中运行的,这大大提升了高数据量web访问的访问速度。然而mc只是提供了简单的数据结构,比如 string存储;Redis却提供了大量的数据结构,比如string、list、set、hashset、sorted set这些,这使得用户方便了好多,毕竟封装了一层实用的功能,同时实现了同样的效果,当然用Redis而慢慢舍弃mc。  内存和硬盘的关系,硬盘放置主体数据用于持久化存储,而内存则是当前运行的那部分数据,CPU访问内存而不是磁盘,这大大提升了运行的速度,当然这是基于程序的局部化访问原理。  推理到 Redis + MySQL,它是内存+磁盘关系的一个映射,MySQL 放在磁盘,Redis放在内存,这样的话,web应用每次只访问Redis,如果没有找到的数据,才去访问 MySQL。  然而 Redis + MySQL 和内存+磁盘的用法最好是不同的。前者是内存数据库,数据保存在内存中,当然速度快。后者是关系型数据库,功能强大,数据访问也就慢。像memcache,MongoDB,Redis,都属于No SQL系列。不是一个类型的东西,应用场景也不太一样,还是要看你的需求来决定。
  • [交流吐槽] Mysql和Mongodb应用场景
    MongoDB 的适用场景为:数据不是特别重要(例如通知,推送这些),数据表结构变化较为频繁,数据量特别大,数据的并发性特别高,数据结构比较特别(例如地图的位置坐标),这些情况下用 MongoDB , 其他情况就还是用 MySQL ,这样组合使用就可以达到最大的效率。1.如果需要将mongodb作为后端db来代替mysql使用,即这里mysql与mongodb 属于平行级别,那么,这样的使用可能有以下几种情况的考量: (1)mongodb所负责部分以文档形式存储,能够有较好的代码亲和性,json格式的直接写入方便。(如日志之类) (2)从data models设计阶段就将原子性考虑于其中,无需事务之类的辅助。开发用如nodejs之类的语言来进行开发,对开发比较方便。 (3)mongodb本身的failover机制,无需使用如MHA之类的方式实现。2.将mongodb作为类似redis ,memcache来做缓存db,为mysql提供服务,或是后端日志收集分析。 考虑到mongodb属于nosql型数据库,sql语句与数据结构不如mysql那么亲和 ,也会有很多时候将mongodb做为辅助mysql而使用的类redis memcache 之类的缓存db来使用。 亦或是仅作日志收集分析。MongoDB 有一个最大的缺点,就是它占用的空间很大,因为它属于典型空间换时间原则的类型。那么它的磁盘空间比普通数据库会浪费一些,而且到目前为止它还没有实现在线压缩功能,在 MongoDB 中频繁的进行数据增删改时,如果记录变了,例如数据大小发生了变化,这时候容易产生一些数据碎片,出现碎片引发的结果,一个是索引会出现性能问题。另外一个就是在一定的时间后,所占空间会莫明其妙地增大,所以要定期把数据库做修复,定期重新做索引,这样会提升MongoDB 的稳定性和效率。1.MySQL 来自女儿的名字; MongoDB 来自 humongous2.MySQL 使用 Table/Row/Column; MongoDB 使用 Collection/Document3.MySQL 需要指定 table 的 schema; MongoDB的 collection 的每个 document 的 schema 可以自由修改4.MySQL 支持 join; MongoDB 没有 join5.MySQL 使用 SQL 语言; MongoDB 使用类似 JavaScript 的函数命令对比MongoDB 与 MySQL 命令对比 传统的关系数据库一般由数据库(database)、表(table)、记录(record)三个层次概念组成,MongoDB 是由数据库(database)、集合(collection)、文档对象(document)三个层次组成。MongoDB对于关系型数据库里的表,但是集合中没有列、行和关系概念,这体现了模式自由的特点。
  • [常见问题汇总帖] 求解,连接华为云服务器上的mysql时项目启动报错
    连接华为云服务器上自己安装的mysql时本机项目启动报错1. 华为云服务器的mysql版本为5.7.382. 华为云服务器的安全组端口已配置,防火墙已放行3. navicat可以正常连接华为云服务器的mysql4. properties配置如下server.port=8088 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://公网ip:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false spring.datasource.username=root spring.datasource.password=密码5. mysql-java-connecter用的是5.1.43报错内容见附件:
  • [已解决问题归档] 【ICD产品】【媒体话单分析】mysql媒体话单表数据问题
    【问题来源】    荣耀项目   【问题简要】文档名称:ICD 产品文档 V300R006C90U3SPC700话单说明.docmysql媒体话单表数据问题【问题类别】 话单【AICC解决方案版本】【期望解决时间】明早【问题现象描述】         基于上述产品文档,在使用该产品时,存在一下问题,方便能否进行确认下:1,媒体呼叫话单表中,有很多电话记录的数据都会存在两条一模一样的重复数据(其他业务表中也是)。而且电话记录中,很多无device-type等于队列和ivr的记录;2,媒体呼叫话单表中,callidnum = -1 的记录中,realeaseCause值在文档中很多找不着说明含义;3,媒体呼叫话单表中,如果判断该通电话有没有进行过转接、三方、保持等操作。4,坐席操作详单中,表字段和文档中的字段均不相同。
  • [已解决问题归档] 【ICD产品】【媒体话单分析】mysql媒体话单表数据问题
    文档名称:ICD 产品文档 V300R006C90U3SPC700话单说明.doc基于上述产品文档,在使用该产品时,存在一下问题,方便能否进行确认下:1,媒体呼叫话单表中,有很多电话记录的数据都会存在两条一模一样的重复数据(其他业务表中也是)。而且电话记录中,很多无device-type等于队列和ivr的记录;2,媒体呼叫话单表中,callidnum = -1 的记录中,realeaseCause值在文档中很多找不着说明含义;3,媒体呼叫话单表中,如果判断该通电话有没有进行过转接、三方、保持等操作。4,坐席操作详单中,表字段和文档中的字段均不相同。
  • [问题求助] GaussDB for MySQL 与MySQL 区别到底是什么?
    想问问论坛的大咖们,GaussDB for MySQL 与 传统的MySQL有啥区别?现在大部分应用场景还是以MySQL为主,不知道GaussDB for MySQL在哪些应用场景或者哪些方面更加有优势呢?有没有使用过GaussDB for MySQL的大牛,能用实例来说明一下。感谢~
  • [问题求助] 【连云港化工智慧园区拓展项目】【Roma连接数据源失败】roma连接本地mysql失败,是否是要开通白名单
    【功能模块】Roma连接数据源【操作步骤&问题现象】1、roma连接本地mysql,失败原因只显示20秒,请先复制到文本文件中,本机的Na 可以连本机的仓库,但是ROMA是外网的,是不是连接不了?【截图信息】【日志信息】(可选,上传日志内容或者附件)
  • [技术干货] MySQL 的数值数据类型
    数值数据类型MySQL支持所有标准的SQL数值数据类型。这些类型包括确切的数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC)以及近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。关键字 INT 是 INTEGER 的同义词,关键字 DEC 和 FIXED 是 DECIMAL 的同义词。MySQL将DOUBLE视为DOUBLE PRECISION(非标准扩展)的同义词。MySQL还将REAL视为DOUBLE PRECISION(非标准变体)的同义词,除非启用了REAL_AS_FLOAT SQL模式。BIT 数据类型存储位值,并且 MyISAM、MEMORY、InnoDB 和 NDB 表支持该数据类型。1 数值数据类型语法对于整数数据类型,M 表示最大显示宽度。最大显示宽度为 255。显示宽度与类型可以存储的值的范围无关,在整数值之间使用减法时,其中一个是 类型 ,除非启用了 sql 模式NO_UNSIGNED_SUBTRACTION,否则结果将是无符号的。请参见第 12.11 节 “强制转换函数和运算符”。UNSIGNED对于浮点和定点数据类型,M 是可以存储的总位数。从MySQL 8.0.17开始,对于整数数据类型,显示宽度属性已弃用;您应该期望在MySQL的未来版本中删除对它的支持。如果为数字列指定,MySQL 会自动将属性添加到列中。ZEROFILLUNSIGNED从MySQL 8.0.17开始,该属性对于数值数据类型已弃用;您应该期望在MySQL的未来版本中删除对它的支持。请考虑使用另一种方法来生成此属性的效果。例如,应用程序可以使用 LPAD() 函数将数字清零到所需的宽度,也可以将格式化的数字存储在 CHAR 列中。ZEROFILL允许该属性的数值数据类型也允许 。但是,默认情况下,这些数据类型是有符号的,因此该属性不起作用。UNSIGNEDSIGNEDSIGNED从MySQL 8.0.17开始,对于FLOAT,DOUBLE和DECIMAL(以及任何同义词)类型的列,UNSIGNEDCHECKSERIAL是 的别名。BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUESERIAL DEFAULT VALUE在整数列的定义中是 的别名。NOT NULL AUTO_INCREMENT UNIQUE。BIT (M)位值类型。M 表示每个值的位数,从 1 到 64。如果省略 M,则默认值为 1。TINYINT一个非常小的整数。有符号范围是 。无符号范围为 。-1281270255布尔值这些类型是 TINYINT(1) 的同义词。值为零被视为 false。非零值被视为真:但是,值 和 分别只是 和 的别名,如下所示:TRUEFALSE10最后两个语句显示显示的结果,因为 既不等于 也不等于 。210SMALLINT一个小整数。有符号范围是 。无符号范围为 。-3276832767065535MEDIDUMINT中等大小的整数。有符号范围是 。无符号范围为 。-83886088388607016777215INT正常大小的整数。有符号范围是 。无符号范围为 。-2147483648214748364704294967295INTEGER此类型是 INT 的同义词。BIGINT一个大整数。有符号范围是 。无符号范围为 。-92233720368547758089223372036854775807018446744073709551615SERIAL是 的别名。BIGINT UNSIGNED NOT NULL AUTO_INCREMENT 关于 BIGINT 列,您应该注意的一些事项:所有算术都是使用有符号 BIGINT 或 DOUBLE 值完成的,因此,除了位函数之外,不应使用大于(63 位)的无符号大整数!如果这样做,结果中的最后一些数字可能是错误的,因为在将 BIGINT 值转换为 DOUBLE 时会出现舍入错误。9223372036854775807MySQL可以在以下情况下处理BIGINT:使用整数在 BIGINT 列中存储较大的无符号值时。在 MIN(col_name) 或 MAX(col_name) 中,col_name 是指 BIGINT 列。使用运算符 (+、-、* 等)时,其中两个操作数都是整数。通过使用字符串存储确切的整数值,您始终可以在 BIGINT 列中存储该值。在这种情况下,MySQL执行字符串到数字的转换,不涉及中间的双精度表示。-、+和 * 运算符在两个操作数都是整数值时使用 BIGINT 算术。这意味着,如果将两个大整数(或返回整数的函数的结果)相乘,则当结果大于 时,可能会得到意外的结果。9223372036854775807DECIMAL打包的“精确”定点数。M 是总位数(精度),D 是小数点(小数位数)之后的数字位数。小数点和(对于负数)符号不计入 M。如果 D 为 0,则值没有小数点或小数部分。DECIMAL 的最大位数 (M) 为 65。支持的最大小数位数 (D) 为 30。如果省略 D,则默认值为 0。如果省略 M,则默认值为 10。.UNSIGNED,如果指定,则不允许负值。从MySQL 8.0.17开始,该属性对于DECIMAL类型的列(以及任何同义词)已弃用;您应该期望在MySQL的未来版本中删除对它的支持。请考虑对此类列使用简单约束。UNSIGNEDCHECKFLOAT一个小的(单精度)浮点数。允许的值为 、 和 to 。这些是基于IEEE标准的理论限制。实际范围可能略小,具体取决于您的硬件或操作系统。-3.402823466E+38-1.175494351E-3801.175494351E-383.402823466E+38M 是总位数,D 是小数点后的位数。如果省略 M 和 D,则值将存储到硬件允许的限制。单精度浮点数精确到大约 7 位小数。FLOAT(M,D)是一个非标准的 MySQL 扩展。从MySQL 8.0.17开始,此语法已弃用,UNSIGNED,如果指定,则不允许负值。从MySQL 8.0.17开始,该属性对于FLOAT类型的列(以及任何同义词)已被弃用,使用FLOAT可能会给你一些意想不到的问题,因为MySQL中的所有计算都是以双精度完成的DOUBLE正常大小(双精度)浮点数。允许的值为 、 和 to 。这些是基于IEEE标准的理论限制。实际范围可能略小,具体取决于您的硬件或操作系统。-1.7976931348623157E+308-2.2250738585072014E-30802.2250738585072014E-3081.7976931348623157E+308M 是总位数,D 是小数点后的位数。如果省略 M 和 D,则值将存储到硬件允许的限制。双精度浮点数精确到小数点后约 15 位。DOUBLE(M,D)是一个非标准的 MySQL 扩展。从MySQL 8.0.17开始,此语法已弃用UNSIGNED,如果指定,则不允许负值。从MySQL 8.0.17开始,该属性对于DOUBLE类型的列(以及任何同义词)已弃用。
  • [技术干货] mysql8.x docker远程访问配置详解
    本文主要介绍了mysql8.x docker远程访问配置,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下目录• 环境情况 • 遇到的错误 • 解决方法 • 1. 登录 mysql docker 内部 • 2. 设置root密码 • 3. 设置 root 远程访问权限 • 4. 设置普通用户 myuser 的远程访问 环境情况mysql 8.x 是通过 docker 方式部署的,启动的 docker-compose.yml 如下:1234567891011121314151617181920212223242526version: "3.2"services:    mysql:        container_name: mysql        image: "mysql:8.0"        ports:            - "3306:3306"        command:            [                "--character-set-server=utf8mb4",                "--collation-server=utf8mb4_unicode_ci",                "--sql_mode=STRICT_TRANS_TABLES,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION",            ]        volumes:            - type: bind              source: ./mysql              target: /var/lib/mysql            - type: bind              source: ./mysql-docker.cnf              target: /etc/mysql/conf.d/docker.cnf        environment:            - MYSQL_RANDOM_ROOT_PASSWORD=yes            - MYSQL_USER=myuser            - MYSQL_PASSWORD=mypass            - MYSQL_DATABASE=mydb        restart: always首次通过 docker-compose 命令启动时,会自动下载 mysql 8.x 的镜像。启动成功之后,可以看到 3306 端口也映射出来了。这时,mysql 算是正常安装启动了。​遇到的错误接下来,通过 navicat 之类的数据库客户端来连接 mysql 服务器的时候,发现根本连不上,遇到的错误种类有:1. ERROR 1045 (28000): Access denied for user 'myuser'2. 10060 错误3. 10061 错误解决方法网上有很多通过设置数据库用户的权限来解决远程访问的问题的,但是只有核心的步骤,缺少过程。1. 登录 mysql docker 内部从上面的 docker-compose.yml 可以看出,并没有配置 mysql root 用户的密码。在 volumn 映射那段,可以看到,我们把容器中的 /etc/mysql/conf.d/docker.cnf 文件映射到外部了。此文件的内容如下:123[mysqld]skip-host-cacheskip-name-resolve添加一行如下,这样登录 mysql 就不需要密码了。1234[mysqld]skip-host-cacheskip-name-resolveskip-grant-tables添加后,重启容器。12docker-compose downdocker-compose up -d2. 设置root密码进入容器,并用 root 账户登录 mysql 服务器。1234567891011docker exec -it mysql /bin/bashmysql -uroot   # 这里直接回车,不用输入密码就可以登入服务器 mysql> flush privileges;Query OK, 0 rows affected (0.00 sec) mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mysqlroot';Query OK, 0 rows affected (0.01 sec) mysql> flush privileges;Query OK, 0 rows affected (0.00 sec)注意,这里要先执行一次 flush privileges; 否则修改密码不会成功。​然后,退出容器,恢复映射出的 /etc/mysql/conf.d/docker.cnf 文件。123[mysqld]skip-host-cacheskip-name-resolve把新加的那行删掉,再重启容器。12docker-compose downdocker-compose up -d3. 设置 root 远程访问权限重启容器之后,再次进入容器,设置 root 用户的远程访问权限。12345678docker exec -it mysql /bin/bashmysql -uroot -p    # 需要输入上一步配置的密码 mysqlroot mysql>  ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'mysqlroot';Query OK, 0 rows affected (0.00 sec) mysql> flush privileges;Query OK, 0 rows affected (0.00 sec)配置远程访问的权限用 'root'@'%'  , 而不是上一步的 'root'@'localhost' ​设置之后,不用重启 mysql docker 容器,可以用 navicat 连接上了。4. 设置普通用户 myuser 的远程访问接着上面的操作配置普通用户 myuser 的远程连接。1234567891011mysql>  ALTER USER 'myuser'@'%' IDENTIFIED WITH mysql_native_password BY 'mypass';Query OK, 0 rows affected (0.00 sec) mysql> flush privileges;Query OK, 0 rows affected (0.00 sec) mysql> grant all privileges on *.* to 'myuser'@'%' with grant option;Query OK, 0 rows affected (0.00 sec) mysql> flush privileges;Query OK, 0 rows affected (0.01 sec)设置成功的话,myuser 账户也可以通过 navicat 来远程连接了。转载自https://www.jb51.net/article/233359.htm
  • [技术干货] Ubuntu 18.04.4安装mysql的过程详解 亲测可用
    这篇文章主要介绍了Ubuntu 18.04.4安装mysql-亲测可用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下下面看下Ubuntu 18.04.4安装mysql的过程,内容如下所示:11 sudo apt-get update12 sudo apt-get install mysql-server1234567891011121314151617181920212223242526273 sudo mysql_secure_installation # 初始化配置#1VALIDATE PASSWORD PLUGIN can be used to test passwords...Press y|Y for Yes, any other key for No: N (我的选项)#2Please set the password for root here...New password: (输入密码)Re-enter new password: (重复输入)#3By default, a MySQL installation has an anonymous user,allowing anyone to log into MySQL without having to havea user account created for them...Remove anonymous users? (Press y|Y for Yes, any other key for No) : N (我的选项)#4Normally, root should only be allowed to connect from'localhost'. This ensures that someone cannot guess atthe root password from the network...Disallow root login remotely? (Press y|Y for Yes, any other key for No) : Y (我的选项)#5By default, MySQL comes with a database named 'test' thatanyone can access...Remove test database and access to it? (Press y|Y for Yes, any other key for No) : N (我的选项)#6Reloading the privilege tables will ensure that all changesmade so far will take effect immediately.Reload privilege tables now? (Press y|Y for Yes, any other key for No) : Y (我的选项)4 systemctl status mysql.service # 检查服务器状态14 systemctl status mysql.service # 检查服务器状态running代表无问题12345675 修改mysql 端口号以及将监听地址改为所有  vim /etc/mysql/mysql.conf.d/mysqld.cnf # 编辑配置文件 bind-address            = 0.0.0.0  #将监听ip修改为所有 port            = 3388  # 监听端口修改为3388,可以不改我这是为了安全修改完毕之后重启服务systemctl restart mysql.service123456789101112131415166 开放mysql远程访问1 登录数据库mysql -u root -p 2 切换到数据库mysqluse mysql3 删除匿名用户delete from user where user='';4 增加允许远程访问的用户或者允许现有用户的远程访问给root授予在任意主机(%)访问任意数据库的所有权限mysql> grant all privileges on *.* to 'root'@'%' identified by '这里替换成你想要设置的密码' with grant option;flush privileges;5 退出数据库mysql> exit6 重启数据库sudo service mysql restart到此这篇关于Ubuntu 18.04.4安装mysql的过程详解 亲测可用的文章就介绍到这了转载自https://www.jb51.net/article/233438.htm
  • [其他] 管控面mysql数据库磁盘使用率高或者达到100%
    【问题现象】管控面数据库磁盘使用率高或者达到100%【问题原因】审计日志设置不合理,占用磁盘很多【恢复方案】1.进入审计日志目录,清理审计日志文件(DWS-DB-01和DWS-DB-02)。    cd /var/log/auditrm -rf *.log*    cd /data/ ; du -sh audit.log   //查看对应的审计日志大小    echo "">audit.log  //清空审计日志2.以root用户回到DWS-DB01节点,切到mysql用户,登录本地数据库。    su - mysql    mysql -uroot -p{密码} -S /data/mysql/tmp/mysql.sock3.执行    set global audit_log_rotations=50;    set global audit_log_rotate_on_size=20971520;4.退出数据库,修改配置文件,保证重启也生效vim /data/mysql/etc/my.cnf增加审计日志轮转参数     audit_log_rotations=50     audit_log_rotate_on_size=20971520    保存退出。5.观察审计日志是否开始轮转。6.该参数是单节点生效,需要在每个节点执行。7.(选做)如果不需要审计功能,可以登录库后设置关闭set globalaudit_log_policy=none; 每个节点都需要执行,该步骤请谨慎选择。
  • [知识分享] 【数据库系列】一文了解MySQL的Buffer Pool
    本文分享自华为云社区《[MySQL 的 Buffer Pool,终于被我搞懂了](https://bbs.huaweicloud.com/blogs/338983?utm_source=csdn&utm_medium=bbs-ex&utm_campaign=other&utm_content=content)》,作者:小林coding 。 今天就聊 MySQL 的 Buffer Pool,发车! ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780222689912915.png) # 为什么要有 Buffer Pool? 虽然说 MySQL 的数据是存储在磁盘里的,但是也不能每次都从磁盘里面读取数据,这样性能是极差的。 要想提升查询性能,加个缓存就行了嘛。所以,当数据从磁盘中取出后,缓存内存中,下次查询同样的数据的时候,直接从内存中读取。 为此,Innodb 存储引擎设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780239162222746.png) 有了缓冲池后: - 当读取数据时,如果数据存在于 Buffer Pool 中,客户端就会直接读取 Buffer Pool 中的数据,否则再去磁盘中读取。 - 当修改数据时,首先是修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页,最后由后台线程将脏页写入到磁盘。 **Buffer Pool 有多大?** Buffer Pool 是在 MySQL 启动的时候,向操作系统申请的一片连续的内存空间,默认配置下 Buffer Pool 只有 128MB 。 可以通过调整 innodb_buffer_pool_size 参数来设置 Buffer Pool 的大小,一般建议设置成可用物理内存的 60%~80%。 **Buffer Pool 缓存什么?** InnoDB 会把存储的数据划分为若干个「页」,以页作为磁盘和内存交互的基本单位,一个页的默认大小为 16KB。因此,Buffer Pool 同样需要按「页」来划分。 在 MySQL 启动的时候,**InnoDB 会为 Buffer Pool 申请一片连续的内存空间,然后按照默认的16KB的大小划分出一个个的页, Buffer Pool 中的页就叫做缓存页。** 此时这些缓存页都是空闲的,之后随着程序的运行,才会有磁盘上的页被缓存到 Buffer Pool 中。 所以,MySQL 刚启动的时候,你会观察到使用的虚拟内存空间很大,而使用到的物理内存空间却很小,这是因为只有这些虚拟内存被访问后,操作系统才会触发缺页中断,接着将虚拟地址和物理地址建立映射关系。 Buffer Pool 除了缓存「索引页」和「数据页」,还包括了 undo 页,插入缓存、自适应哈希索引、锁信息等等。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780285425439818.png) 为了更好的管理这些在 Buffer Pool 中的缓存页,InnoDB 为每一个缓存页都创建了一个控制块,控制块信息包括「缓存页的表空间、页号、缓存页地址、链表节点」等等。 控制块也是占有内存空间的,它是放在 Buffer Pool 的最前面,接着才是缓存页,如下图: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780297963834576.png) 上图中控制块和缓存页之间灰色部分称为碎片空间。 >为什么会有碎片空间呢? 你想想啊,每一个控制块都对应一个缓存页,那在分配足够多的控制块和缓存页后,可能剩余的那点儿空间不够一对控制块和缓存页的大小,自然就用不到喽,这个用不到的那点儿内存空间就被称为碎片了。 当然,如果你把 Buffer Pool 的大小设置的刚刚好的话,也可能不会产生碎片。 >查询一条记录,就只需要缓冲一条记录吗? 不是的。 当我们查询一条记录时,InnoDB 是会把整个页的数据加载到 Buffer Pool 中,因为,通过索引只能定位到磁盘中的页,而不能定位到页中的一条记录。将页加载到 Buffer Pool 后,再通过页里的页目录去定位到某条具体的记录。 关于页结构长什么样和索引怎么查询数据的问题可以在这篇找到答案:换一个角度看 B+ 树 # 如何管理 Buffer Pool? ## 如何管理空闲页? Buffer Pool 是一片连续的内存空间,当 MySQL 运行一段时间后,这片连续的内存空间中的缓存页既有空闲的,也有被使用的。 那当我们从磁盘读取数据的时候,总不能通过遍历这一片连续的内存空间来找到空闲的缓存页吧,这样效率太低了。 所以,为了能够快速找到空闲的缓存页,可以使用链表结构,将空闲缓存页的「控制块」作为链表的节点,这个链表称为 Free 链表(空闲链表)。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780336681229269.png) Free 链表上除了有控制块,还有一个头节点,该头节点包含链表的头节点地址,尾节点地址,以及当前链表中节点的数量等信息。 Free 链表节点是一个一个的控制块,而每个控制块包含着对应缓存页的地址,所以相当于 Free 链表节点都对应一个空闲的缓存页。 有了 Free 链表后,每当需要从磁盘中加载一个页到 Buffer Pool 中时,就从 Free链表中取一个空闲的缓存页,并且把该缓存页对应的控制块的信息填上,然后把该缓存页对应的控制块从 Free 链表中移除。 ## 如何管理脏页? 设计 Buffer Pool 除了能提高读性能,还能提高写性能,也就是更新数据的时候,不需要每次都要写入磁盘,而是将 Buffer Pool 对应的缓存页标记为脏页,然后再由后台线程将脏页写入到磁盘。 那为了能快速知道哪些缓存页是脏的,于是就设计出 Flush 链表,它跟 Free 链表类似的,链表的节点也是控制块,区别在于 Flush 链表的元素都是脏页。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780359889467724.png) 有了 Flush 链表后,后台线程就可以遍历 Flush 链表,将脏页写入到磁盘。 ## 如何提高缓存命中率? Buffer Pool 的大小是有限的,对于一些频繁访问的数据我们希望可以一直留在 Buffer Pool 中,而一些很少访问的数据希望可以在某些时机可以淘汰掉,从而保证 Buffer Pool 不会因为满了而导致无法再缓存新的数据,同时还能保证常用数据留在 Buffer Pool 中。 要实现这个,最容易想到的就是 LRU(Least recently used)算法。 该算法的思路是,链表头部的节点是最近使用的,而链表末尾的节点是最久没被使用的。那么,当空间不够了,就淘汰最久没被使用的节点,从而腾出空间。 简单的 LRU 算法的实现思路是这样的: - 当访问的页在 Buffer Pool 里,就直接把该页对应的 LRU 链表节点移动到链表的头部。 - 当访问的页不在 Buffer Pool 里,除了要把页放入到 LRU 链表的头部,还要淘汰 LRU 链表末尾的节点。 比如下图,假设 LRU 链表长度为 5,LRU 链表从左到右有 1,2,3,4,5 的页。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780389178259820.png) 如果访问了 3 号的页,因为 3 号页在 Buffer Pool 里,所以把 3 号页移动到头部即可。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780396047813554.png) 而如果接下来,访问了 8 号页,因为 8 号页不在 Buffer Pool 里,所以需要先淘汰末尾的 5 号页,然后再将 8 号页加入到头部。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780403127560781.png) 到这里我们可以知道,Buffer Pool 里有三种页和链表来管理数据。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780411247848199.png) 图中: - Free Page(空闲页),表示此页未被使用,位于 Free 链表; - Clean Page(干净页),表示此页已被使用,但是页面未发生修改,位于LRU 链表。 - Dirty Page(脏页),表示此页「已被使用」且「已经被修改」,其数据和磁盘上的数据已经不一致。当脏页上的数据写入磁盘后,内存数据和磁盘数据一致,那么该页就变成了干净页。脏页同时存在于 LRU 链表和 Flush 链表。 简单的 LRU 算法并没有被 MySQL 使用,因为简单的 LRU 算法无法避免下面这两个问题: - 预读失效; - Buffer Pool 污染; >什么是预读失效? 先来说说 MySQL 的预读机制。程序是有空间局部性的,靠近当前被访问数据的数据,在未来很大概率会被访问到。 所以,MySQL 在加载数据页时,会提前把它相邻的数据页一并加载进来,目的是为了减少磁盘 IO。 但是可能这些**被提前加载进来的数据页,并没有被访问**,相当于这个预读是白做了,这个就是**预读失效**。 如果使用简单的 LRU 算法,就会把预读页放到 LRU 链表头部,而当 Buffer Pool空间不够的时候,还需要把末尾的页淘汰掉。 如果这些预读页如果一直不会被访问到,就会出现一个很奇怪的问题,不会被访问的预读页却占用了 LRU 链表前排的位置,而末尾淘汰的页,可能是频繁访问的页,这样就大大降低了缓存命中率。 >怎么解决预读失效而导致缓存命中率降低的问题? 我们不能因为害怕预读失效,而将预读机制去掉,大部分情况下,局部性原理还是成立的。 要避免预读失效带来影响,最好就是**让预读的页停留在 Buffer Pool 里的时间要尽可能的短,让真正被访问的页才移动到 LRU 链表的头部,从而保证真正被读取的热数据留在 Buffer Pool 里的时间尽可能长。** 那到底怎么才能避免呢? MySQL 是这样做的,它改进了 LRU 算法,将 LRU 划分了 2 个区域:**old 区域 和 young 区域。** young 区域在 LRU 链表的前半部分,old 区域则是在后半部分,如下图: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780486925903376.png) old 区域占整个 LRU 链表长度的比例可以通过 innodb_old_blocks_pc 参数来设置,默认是 37,代表整个 LRU 链表中 young 区域与 old 区域比例是 63:37。 **划分这两个区域后,预读的页就只需要加入到 old 区域的头部,当页被真正访问的时候,才将页插入 young 区域的头部。** 如果预读的页一直没有被访问,就会从 old 区域移除,这样就不会影响 young 区域中的热点数据。 接下来,给大家举个例子。 假设有一个长度为 10 的 LRU 链表,其中 young 区域占比 70 %,old 区域占比 20 %。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780504634421118.png) 现在有个编号为 20 的页被预读了,这个页只会被插入到 old 区域头部,而 old 区域末尾的页(10号)会被淘汰掉。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780511430704106.png) 如果 20 号页一直不会被访问,它也没有占用到 young 区域的位置,而且还会比 young 区域的数据更早被淘汰出去。 如果 20 号页被预读后,立刻被访问了,那么就会将它插入到 young 区域的头部,young 区域末尾的页(7号),会被挤到 old 区域,作为 old 区域的头部,这个过程并不会有页被淘汰。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780522647328361.png) 虽然通过划分 old 区域 和 young 区域避免了预读失效带来的影响,但是还有个问题无法解决,那就是 Buffer Pool 污染的问题。 >什么是 Buffer Pool 污染? 当某一个 SQL 语句**扫描了大量的数据**时,在 Buffer Pool 空间比较有限的情况下,可能会将 **Buffer Pool 里的所有页都替换出去,导致大量热数据被淘汰了**,等这些热数据又被再次访问的时候,由于缓存未命中,就会产生大量的磁盘 IO,MySQL 性能就会急剧下降,这个过程被称为 **Buffer Pool 污染**。 注意, Buffer Pool 污染并不只是查询语句查询出了大量的数据才出现的问题,即使查询出来的结果集很小,也会造成 Buffer Pool 污染。 比如,在一个数据量非常大的表,执行了这条语句: `select * from t_user where name like "%xiaolin%";` 可能这个查询出来的结果就几条记录,但是由于这条语句会发生索引失效,所以这个查询过程是全表扫描的,接着会发生如下的过程: - 从磁盘读到的页加入到 LRU 链表的 old 区域头部; - 当从页里读取行记录时,也就是页被访问的时候,就要将该页放到 young 区域头部; - 接下来拿行记录的 name 字段和字符串 xiaolin 进行模糊匹配,如果符合条件,就加入到结果集里; - 如此往复,直到扫描完表中的所有记录。 经过这一番折腾,原本 young 区域的热点数据都会被替换掉。 举个例子,假设需要批量扫描:21,22,23,24,25 这五个页,这些页都会被逐一访问(读取页里的记录)。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780590278722758.png) 在批量访问这些数据的时候,会被逐一插入到 young 区域头部。 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20224/1/1648780597849888233.png) 可以看到,原本在 young 区域的热点数据 6 和 7 号页都被淘汰了,这就是 Buffer Pool 污染的问题。 >怎么解决出现 Buffer Pool 污染而导致缓存命中率下降的问题? 像前面这种全表扫描的查询,很多缓冲页其实只会被访问一次,但是它却只因为被访问了一次而进入到 young 区域,从而导致热点数据被替换了。 LRU 链表中 young 区域就是热点数据,只要我们提高进入到 young 区域的门槛,就能有效地保证 young 区域里的热点数据不会被替换掉。 MySQL 是这样做的,进入到 young 区域条件增加了一个**停留在 old 区域的时间判断**。 具体是这样做的,在对某个处在 old 区域的缓存页进行第一次访问时,就在它对应的控制块中记录下来这个访问时间: - 如果后续的访问时间与第一次访问的时间**在某个时间间隔内,那么该缓存页就不会被从 old 区域移动到 young 区域的头部**; - 如果后续的访问时间与第一次访问的时间**不在某个时间间隔内,那么该缓存页移动到 young 区域的头部**; 这个间隔时间是由 innodb_old_blocks_time 控制的,默认是 1000 ms。 也就说,**只有同时满足「被访问」与「在 old 区域停留时间超过 1 秒」两个条件,才会被插入到 young 区域头部**,这样就解决了 Buffer Pool 污染的问题 。 另外,MySQL 针对 young 区域其实做了一个优化,为了防止 young 区域节点频繁移动到头部。young 区域前面 1/4 被访问不会移动到链表头部,只有后面的 3/4被访问了才会。 ## 脏页什么时候会被刷入磁盘? 引入了 Buffer Pool 后,当修改数据时,首先是修改 Buffer Pool 中数据所在的页,然后将其页设置为脏页,但是磁盘中还是原数据。 因此,脏页需要被刷入磁盘,保证缓存和磁盘数据一致,但是若每次修改数据都刷入磁盘,则性能会很差,因此一般都会在一定时机进行批量刷盘。 可能大家担心,如果在脏页还没有来得及刷入到磁盘时,MySQL 宕机了,不就丢失数据了吗? 这个不用担心,InnoDB 的更新操作采用的是 Write Ahead Log 策略,即先写日志,再写入磁盘,通过 redo log 日志让 MySQL 拥有了崩溃恢复能力。 下面几种情况会触发脏页的刷新: - 当 redo log 日志满了的情况下,会主动触发脏页刷新到磁盘; - Buffer Pool 空间不足时,需要将一部分数据页淘汰掉,如果淘汰的是脏页,需要先将脏页同步到磁盘; - MySQL 认为空闲时,后台线程回定期将适量的脏页刷入到磁盘; - MySQL 正常关闭之前,会把所有的脏页刷入到磁盘; 在我们开启了慢 SQL 监控后,如果你发现**「偶尔」会出现一些用时稍长的 SQL**,这可能是因为脏页在刷新到磁盘时可能会给数据库带来性能开销,导致数据库操作抖动。 如果间断出现这种现象,就需要调大 Buffer Pool 空间或 redo log 日志的大小。 # 总结 Innodb 存储引擎设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能。 Buffer Pool 以页为单位缓冲数据,可以通过 innodb_buffer_pool_size 参数调整缓冲池的大小,默认是 128 M。 Innodb 通过三种链表来管理缓页: - Free List (空闲页链表),管理空闲页; - Flush List (脏页链表),管理脏页; - LRU List,管理脏页+干净页,将最近且经常查询的数据缓存在其中,而不常查询的数据就淘汰出去。; InnoDB 对 LRU 做了一些优化,我们熟悉的 LRU 算法通常是将最近查询的数据放到 LRU 链表的头部,而 InnoDB 做 2 点优化: - 将 LRU 链表 分为young 和 old 两个区域,加入缓冲池的页,优先插入 old 区域;页被访问时,才进入 young 区域,目的是为了解决预读失效的问题。 - 当「页被访问」且「 old 区域停留时间超过 innodb_old_blocks_time 阈值(默认为1秒)」时,才会将页插入到 young 区域,否则还是插入到 old 区域,目的是为了解决批量数据访问,大量热数据淘汰的问题。 可以通过调整 innodb_old_blocks_pc 参数,设置 young 区域和 old 区域比例。 在开启了慢 SQL 监控后,如果你发现「偶尔」会出现一些用时稍长的 SQL,这可因为脏页在刷新到磁盘时导致数据库性能抖动。如果在很短的时间出现这种现象,就需要调大 Buffer Pool 空间或 redo log 日志的大小。
  • [方案分享] RDS MySQL通过DRS同 region跨账号迁移
    ## 场景描述 当前分享包含以下内容: - 如何通过对等连接打通两个账号的VPC,以及数据库网络 - 通过DRS 实现数据库的数据迁移 说明:当前使用场景为同一个region 不同账号下的RDS数据迁移;若场景为同一账号下相同region不同 Vpc 间的数据迁移,使用DRS VPC网络进行数据迁移,详细操作可参考链接:[https://support.huaweicloud.com/prepare-drs/drs_02_0480.html](https://support.huaweicloud.com/prepare-drs/drs_02_0480.html) ## 实现原理 ![同region跨账号复制RDS.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/30/1648620874382151908.png) RDS 同 region 跨账号数据迁移原理: 使用对等连接(同region使用)打通两个账号之间的VPC网络,使用DRS VPN、专线网络模型实现内网数据库的数据迁移。 ## 服务列表 - 虚拟私有有云 VPC - 对等连接 - 云数据库 RDS - 数据复制服务 DRS ## 操作流程 - 流程图 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/30/1648626929631785120.png) #### 详细操作见附件
  • [已解决问题归档] ideploy加载cms脚本显示成功,ideploy无加载cms表空间日志,cms数据库也无表
    【功能模块】局点:中讯网联AICC版本:8.15.0Mysql:5.7.34Breeze_iDeploy_:V100R003C05SPC630mysql驱动:mysql-connector-java-5.1.49.jar问题:ideploy加载cms脚本显示成功,ideploy无加载cms表空间日志,cms数据库也无表;(但是sum脚本刷成功了,sum数据库和cms数据库为同一台mysql数据库服务器)(1)目标主机(mysql数据库)cmsmysqlInstall.log无日志打印。(2) 目标主机(mysql数据库)/tmp下面也是放了mysql驱动的
  • [技术干货] 如何使用pgloader迁移MySQL数据库至openGauss
    pgloader介绍pgloader是一个数据导入工具,使用COPY命令将数据导入到PostgreSQL。pgloader有两种工作模式,一种是从文件导入,一种是迁移数据库。pgloader在两种情况下都使用PostgreSQL的COPY协议高效的传输数据。openGauss兼容PostgreSQL的通信协议以及绝大部分语法,可使用pgloader将MySQL数据库迁移至openGauss。pgloader在openGauss上的问题由于openGauss 对原生PostgreSQL的通信协议进行了安全加固,这导致与PostgreSQL的默认通信协议互相不兼容了,因此,使用pgloader的PostgreSQL原生版本默认是不能连接openGauss的。会报类似下述错误:处理方式是通过修改GUC进行规避,涉及的GUC参数是password_encryption_type,PostgreSQL默认的加密方式是md5,由于md5已经不安全了,为了提高openGauss的安全能力,openGauss支持sha256, 并且默认是sha256的加密方式,这就导致了上述报错。但是openGauss并没有删除md5的加密和验证逻辑,因此,是可以通过修改该GUC参数开启md5加密方式的。开启方法:gs_guc reload -D $PGDATA -c "password_encryption_type = 1"一定要在设置完上述参数后,再新建用户。然后就可以使用该新建用户登录数据库了。接下来我们将演示如何使用pgloader迁移MySQL数据库至openGauss。安装pgloader您可以直接从 apt.postgresql.org 和官方 debian 存储库 packages.debian.org/pgloader 安装 pgloader。$ apt-get install pgloader同时,您也可以通过 docker image 使用pgloader。$ docker pull dimitri/pgloader $ docker run --rm --name pgloader dimitri/pgloader:latest pgloader --version $ docker run --rm --name pgloader dimitri/pgloader:latest pgloader –help配置pgloaderpgloader提供丰富的配置项,您可以自由定义迁移时的各类动作,如通过include drop,删除目标数据库中名称出现在MySQL数据库中的所有表,以允许连续多次使用同一命令,从干净的环境自动启动。这里简单介绍几个常用的配置项。FROM:源数据库的连接URL,格式如下:mysql://[user[:password]@][netloc][:port][/dbname][?option=value&...]INTO:目标数据库的连接URL,格式如下: postgresql://[user[:password]@][netloc][:port][/dbname][?option=value&...]WITH:从MySQL数据库加载时的选项。有include drop、create tables、create indexes等选项。CAST:用户自定义类型转换规则。允许用户覆盖已有的默认转换规则或者使用特殊情况修改它们。部分迁移:用户可以通过 including only table names matching 和 excluding table names matching 实现只迁移特定的表或者在迁移过程中排除特定的表。详细的配置项解读,可查看官网的说明:https://pgloader.readthedocs.io/en/latest/ref/mysql.html下面是一份从MySQL迁移到openGauss的配置文件示例:LOAD DATABASE FROM mysql://mysql_test:password123@1.1.1.1:3306/mysql_database INTO postgresql://opengauss_test:password_123@1.1.1.1:5432/opengauss_database WITH include drop, create tables, create indexes, reset no sequences, workers = 8, concurrency = 1, multiple readers per thread, rows per range = 50000 CAST type varchar when(= 1 precision) to "boolean" drop typemod keep default keep not null;以上配置文件的含义是,迁移数据时,MySQL侧使用的用户名密码分别是 mysql_test 和 password123。MySQL服务器的IP和port分别是1.1.1.1和3306,待迁移的数据库是mysql_database。openGauss侧使用的用户名密码分别是 opengauss_test 和 password_123。openGauss服务器的IP和port分别是1.1.1.1和5432,目标数据库是opengauss_database。需要注意的是,这里使用的用户需要有远程连接MySQL和openGauss的权限,以及对对应数据库的读写权限。同时对于openGauss,运行pgloader所在的机器需要在openGauss的远程访问白名单中。创建用户及database在openGauss侧创建迁移时需要用到的用户以及database。运行pgloader进行数据迁移以下演示基于使用docker image方式安装的pgloader。将前面准备好的配置文件命名为 openGauss.loader。启动docker:docker run -tid --name pgloader_test dimitri/pgloader 复制配置文件到docker:docker cp ./openGauss.loader pgloader_test:/ 进入docker环境:docker exec -it pgloader_test /bin/bash启动pgloader,等待数据迁移完成,查看迁移结果报告:pgloader openGauss.loader在openGauss侧查看迁移结果:
总条数:1406 到第
上滑加载中