• [交流吐槽] 聚簇索引和非聚簇索引到底有什么区别?
    在 MySQL 的 InnoDB 引擎中,每个索引都会对应一颗 B+ 树,而聚簇索引和非聚簇索引最大的区别在于叶子节点存储的数据不同,聚簇索引叶子节点存储的是行数据,因此通过聚簇索引可以直接找到真正的行数据。在 MySQL 默认引擎 InnoDB 中,索引大致可分为两类:聚簇索引和非聚簇索引,它们的区别也是常见的面试题,所以我们今天就来盘它们。聚簇索引聚簇索引(Clustered Index)一般指的是主键索引(如果存在主键索引的话),聚簇索引也被称之为聚集索引。聚簇索引在 InnoDB 中是使用 B+ 树实现的,比如我们创建一张 student 表,它的构建 SQL 如下:drop table if exists student; create table student( id int primary key, name varchar(16), class_id int not null, index (class_id) )engine=InnoDB; -- 添加测试数据 insert into student(id,name,class_id) values(1,'张三',100), (2,'李四',200),(3,'王五',300);以上 student 表中有一个聚簇索引(也就是主键索引)id,和一个非聚簇索引 class_id。聚簇索引 id 对应的 B+ 树如下图所示:在聚簇索引的叶子节点直接存储用户信息的内存地址,我们使用内存地址可以直接找到相应的行数据。非聚簇索引非聚簇索引在 InnoDB 引擎中,也叫二级索引,以上面 student 表为例,在 student 中非聚簇索引 class_id 对应 B+ 树如下图所示:从上图我们可以看出,在非聚簇索引的叶子节点上存储的并不是真正的行数据,而是主键 ID,所以当我们使用非聚簇索引进行查询时,首先会得到一个主键 ID,然后再使用主键 ID 去聚簇索引上找到真正的行数据,我们把这个过程称之为回表查询。总结在 MySQL 的 InnoDB 引擎中,每个索引都会对应一颗 B+ 树,而聚簇索引和非聚簇索引最大的区别在于叶子节点存储的数据不同,聚簇索引叶子节点存储的是行数据,因此通过聚簇索引可以直接找到真正的行数据;而非聚簇索引叶子节点存储的是主键信息,所以使用非聚簇索引还需要回表查询,因此我们可以得出聚簇索引和非聚簇索引的区别主要有以下几个:聚簇索引叶子节点存储的是行数据;而非聚簇索引叶子节点存储的是聚簇索引(通常是主键 ID)。聚簇索引查询效率更高,而非聚簇索引需要进行回表查询,因此性能不如聚簇索引。聚簇索引一般为主键索引,而主键一个表中只能有一个,因此聚簇索引一个表中也只能有一个,而非聚簇索引则没有数量上的限制。
  • [交流吐槽] 几种常用关系型数据库介绍
    数据库管理系统是用于创建,维护与管理数据库的系统软件,是搭建其他应用环境所必备的软件之一,是软件系统架构的重要组成部分。对于IT人员,不论是开发还是测试人员都是其必须掌握的软件。对于开发可以说是他们吃饭的家伙,对于测试人员可以说是测试利器。目前,商品化的数据库管理系统以关系型数据库为主导产品,技术比较成熟。面向对象的数据库管理系统虽然技术先进,数据库易于开发、维护,但尚未有成熟的产品。今天我们就专门来聊一聊常见的关系型数据库管理系统都有哪些,各自有什么特点。一、MySQLMySQL是最受欢迎的开源SQL数据库管理系统,它由 MySQL AB开发、发布和支持。MySQL AB是一家基于MySQL开发人员的商业公司,它是一家使用了一种成功的商业模式来结合开源价值和方法论的第二代开源公司。MySQL是MySQL AB的注册商标。MySQL是一个快速的、多线程、多用户和健壮的SQL数据库服务器。MySQL服务器支持关键任务、重负载生产系统的使用,也可以将它嵌入到一个大配置(mass- deployed)的软件中去。与其他数据库管理系统相比,MySQL具有以下优势:(1)MySQL是一个关系数据库管理系统。(2)MySQL是开源的。(3)MySQL服务器是一个快速的、可靠的和易于使用的数据库服务器。(4)MySQL服务器工作在客户/服务器或嵌入系统中。(5)有大量的MySQL软件可以使用。二、SQL ServerSQL Server是由微软开发的数据库管理系统,是Web上最流行的用于存储数据的数据库,它已广泛用于电子商务、银行、保险、电力等与数据库有关的行业。目前最新版本是SQL Server 2005,它只能在Windows上运行,操作系统的系统稳定性对数据库十分重要。并行实施和共存模型并不成熟,很难处理日益增多的用户数和数据卷,伸缩性有限。SQL Server 提供了众多的Web和电子商务功能,如对XML和Internet标准的丰富支持,通过Web对数据进行轻松安全的访问,具有强大的、灵活的、基于Web的和安全的应用程序管理等。而且,由于其易操作性及其友好的操作界面,深受广大用户的喜爱。三、Oracle提起数据库,第一个想到的公司,一般都会是Oracle(甲骨文)。该公司成立于1977年,最初是一家专门开发数据库的公司。Oracle在数据库领域一直处于领先地位。 1984年,首先将关系数据库转到了桌面计算机上。然后,Oracle5率先推出了分布式数据库、客户/服务器结构等崭新的概念。Oracle 6首创行锁定模式以及对称多处理计算机的支持……最新的Oracle 8主要增加了对象技术,成为关系—对象数据库系统。目前,Oracle产品覆盖了大、中、小型机等几十种机型,Oracle数据库成为世界上使用最广泛的关系数据系统之一。Oracle数据库产品具有以下优良特性:(1)兼容性:Oracle产品采用标准SQL,并经过美国国家标准技术所(NIST)测试。与IBM SQL/DS、DB2、INGRES、IDMS/R等兼容。(2)可移植性:Oracle的产品可运行于很宽范围的硬件与操作系统平台上。可以安装在70种以上不同的大、中、小型机上;可在VMS、DOS、UNIX、Windows等多种操作系统下工作。(3)可联结性:Oracle能与多种通讯网络相连,支持各种协议(TCP/IP、DECnet、LU6.2等)。(4)高生产率:Oracle产品提供了多种开发工具,能极大地方便用户进行进一步的开发。(5)开放性;Oracle良好的兼容性、可移植性、可连接性和高生产率使Oracle RDBMS具有良好的开放性。四、Sybase1984年,Mark B. Hiffman和Robert Epstern创建了Sybase公司,并在1987年推出了Sybase数据库产品。Sybase主要有三种版本:一是UNIX操作系统下运行的版本; 二是Novell Netware环境下运行的版本;三是Windows NT环境下运行的版本。对UNIX操作系统,目前应用最广泛的是SYBASE 10及SYABSE 11 for SCO UNIX。Sybase数据库的特点:(1)它是基于客户/服务器体系结构的数据库。(2)它是真正开放的数据库。(3)它是一种高性能的数据库。五、DB2DB2是内嵌于IBM的AS/400系统上的数据库管理系统,直接由硬件支持。它支持标准的SQL语言,具有与异种数据库相连的GATEWAY。因此它具有速度快、可靠性好的优点。但是,只有硬件平台选择了IBM的AS/400,才能选择使用DB2数据库管理系统。DB2能在所有主流平台上运行(包括Windows),最适于海量数据。DB2在企业级的应用最为广泛,在全球的500家最大的企业中,几乎85%以上都用DB2数据库服务器,而国内到1997年约占5%。除此之外,还有微软的 Access数据库、FoxPro数据库等。既然现在有这么多的数据库系统,那么在游戏编程时应该选择什么样的数据库呢?首要的原则就是根据实际需要,另一方面还要考虑游戏开发预算。现在常用的数据库有:SQL Server、My SQL、Oracle、FoxPro。其中MySQL是一个完全免费的数据库系统,其功能也具备了标准数据库的功能,因此,在独立制作时,建议使用。 Oracle虽然功能强劲,但它毕竟是为商业用途而存在的,目前很少在游戏中使用到。
  • [交流吐槽] 谈谈你对MySQL事务隔离级别的理解
    作者:Tom弹架构         2022-06-10 11:51:49一位5年工作经验的粉丝,去阿里面试被问到一个关于数据库事务隔离级别的问题,当时,没有问答上来,希望给他一个参考答案。那么,今天我给大家谈谈我的理解。另外,我花了1个多星期把往期的面试题解析配套文档准备好了,一共有10W字,想获取的小伙伴可以从我的个人煮叶简介中找到。1.脏读、幻读、不可重复读在SQL操作中,多个事务竞争可能会产生三种不同的现象,分别是脏读、幻读、不可重复读。首先来看脏读,如图所示,假设有两个事务T1/T2同时在执行,T1事务有可能会读取到T2事务未提交的数据,但是未提交的事务T2可能会回滚,也就导致了T1事务读取到最终不一定存在的数据产生脏读的现象。然后来看幻读,如图所示:假设有两个事务T1/T2同时执行,事务T1执行范围查询或者范围修改的过程中,事务T2插入了一条属于事务T1范围内的数据并且提交了,这时候在事务T1查询发现多出来了一条数据,或者在T1事务发现这条数据没有被修改,看起来像是产生了幻觉,这种现象称为幻读。最后来看,不可重复读,如图所示:假设有两个事务T1/T2同时执行,事务T1在不同的时刻读取同一行数据的时候结果可能不一样,从而导致不可重复读的问题。2.事务隔离级别那么事务隔离级别,就是是为了解决多个并行事务竞争, 。而这脏读、幻读、不可重复读这三种现象在实际应用中,有些业务场景是不能接受这些现象存在的,所以在SQL标准中定义了四种隔离级别,分别是:读未提交,在这种隔离级别下,可能会产生脏读、不可重复读、幻读。读已提交(RC),在这种隔离级别下,可能会产生不可重复读和幻读。可重复读(RR),在这种隔离级别下,可能会产生幻读串行化,在这种隔离级别下,多个并行事务串行化执行,不会产生安全性问题。这四种隔离级别里面,只有串行化解决了全部的问题,但这种隔离级别的性能是最低的。在MySQL里面,InnoDB引擎默认的隔离级别是RR(可重复读),因为它需要保证事务ACID特性中的隔离性特征。以上就是我对 MySQL事务隔离级别的理解。我是被编程耽误的文艺Tom,如果我的分享对你有帮助,请动动手指一键三连分享给更多的人。关注我,面试不再难!​
  • [交流吐槽] DBA技术分享--MySQL三个关于主键PrimaryKeys的查询
    概述分享作为DBA日常工作中,关于mysql主键的3个常用查询语句,分别如下:列出 MySQL 数据库中的所有主键 (PK) 及其列。列出用户数据库(模式)中没有主键的表。查询显示了用户数据库(模式)中有多少没有主键的表,以及占总表的百分比。列出 MySQL 数据库中的所有主键 (PK) 及其列select tab.table_schema as database_schema, sta.index_name as pk_name, sta.seq_in_index as column_id, sta.column_name, tab.table_name from information_schema.tables as tab inner join information_schema.statistics as sta on sta.table_schema = tab.table_schema and sta.table_name = tab.table_name and sta.index_name = 'primary' where tab.table_schema = 'your database name' and tab.table_type = 'BASE TABLE' order by tab.table_name, column_id;列说明:table_schema - PK 数据库(模式)名称。pk_name - PK 约束名称。column_id - 索引 (1, 2, ...) 中列的 id。2 或更高表示键是复合键(包含多于一列)。column_name - 主键列名。table_name - PK 表名。输出示例:输出结果说明:一行:代表一个主键列。行范围:数据库中所有 PK 约束的列(模式)。排序方式:表名、列id。列出用户数据库(模式)中没有主键的表select tab.table_schema as database_name, tab.table_name from information_schema.tables tab left join information_schema.table_constraints tco on tab.table_schema = tco.table_schema and tab.table_name = tco.table_name and tco.constraint_type = 'PRIMARY KEY' where tco.constraint_type is null and tab.table_schema not in('mysql', 'information_schema', 'performance_schema', 'sys') and tab.table_type = 'BASE TABLE' -- and tab.table_schema = 'sakila' -- put schema name here order by tab.table_schema, tab.table_name;注意:如果您需要特定数据库(模式)的信息,请取消注释 table_schema 行并提供您的数据库名称。列说明:database_name - 数据库(模式)名称。table_name - 表名。示例:输出结果说明:一行:表示数据库中没有主键的一张表(模式)。行范围:数据库中没有主键的所有表(模式)。排序方式:数据库(模式)名称、表名。查询显示了用户数据库(模式)中有多少没有主键的表,以及占总表的百分比select count(*) as all_tables, count(*) - count(tco.constraint_type) as no_pk_tables, cast( 100.0*(count(*) - count(tco.constraint_type)) / count(*) as decimal(5,2)) as no_pk_percent from information_schema.tables tab left join information_schema.table_constraints tco on tab.table_schema = tco.table_schema and tab.table_name = tco.table_name and tco.constraint_type = 'PRIMARY KEY' where tab.table_type = 'BASE TABLE' -- and tab.table_schema = 'database_name' -- put your database name here and tab.table_schema not in('mysql', 'information_schema', 'sys', 'performance_schema');列说明:all_tables - 数据库中所有表的数量no_pk_tables - 没有主键的表数no_pk_percent - 所有表中没有主键的表的百分比示例:
  • [技术干货] MYSQL的索引和存储引擎[转载]
    MYSQL的索引和存储引擎介绍索引是通过某种算法,构建出一个数据模型,用于快速查出在某个列中有一特定值的行,不使用索引,MYSQL必须从第一行记录开始读完整个表,直到找出相关的行,表越大,查询数据所花费的时间就越多,如果表中查询的列有一个索引,MYSQL能够快速到达一个位置去搜索数据文件,而不必查看所有数据,那么将会节省很大一部分时间.索引类似一本书的目录,比如要查找student这个单词,可以先找到s开头的页然后向后查找,这个就类似索引.索引的分类索引是存储引擎用来快速查找记录的一种数据结构.按照数据结构分:     ① Hash索引    ② B+Tree索引按照功能分:    ① 单列索引        普通索引        唯一索引        主键索引    ② 组合索引    ③ 全文索引    ④ 空间索引单列索引-普通索引单列索引: 一个索引只包含单个列,但一个表中可以有多个单列索引普通索引: MYSQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹是为了查数据更快一点. 创建普通索引:    方式1-创建表的时候直接创建索引        create table student(            sid int primary key,            car_id varchar(20),            name  varchar(20),            index index_name(name) -- 给name列创建索引        );    方式2-直接创建        create index index_name on student(name);    方式3-通过修改表结构添加索引        alert table student add index index_name(name);查看索引:    查看数据库所有的索引        select * from mysql.innodb_index_stats a where a.database_name='数据库名';    查看表中的所有索引        show index from student;删除索引    drop index 索引名 on 表名;    alert table 表名 drop index 索引名;单列索引-唯一索引唯一索引与前面的普通索引类似,不同的就是,索引列的值必须唯一,但允许为空,如果是组合索引,则列值组合必须唯一.    创建普通索引:    方式1-创建表的时候直接创建索引        create table student(            sid int primary key,            car_id varchar(20),            name  varchar(20),            unique index_car_id(car_id) -- 给 car_id 列创建索引        );    方式2-直接创建        create unique index index_car_id on student(car_id);    方式3-通过修改表结构添加索引        alert table student add unique index_car_id(car_id);删除索引    drop index 索引名 on 表名;    alert table 表名 drop index 索引名;单列索引-主键索引每张表一般都会有自己的主键,当我们在创建表时,mysql会自动在主键列上建立一个索引,这就是主键索引,主键是具有唯一性并且不允许为NULL,所以她是一种特殊的唯一索引.1组合索引组合索引也叫复合索引,指的是我们在建立索引的时候使用多个字段,列入同时使用身份证和手机号建立索引,同样的可以建立为普通索引或者唯一索引.复合索引的使用复合最左原则.    创建索引:    create index index_phone_car_id on student(phone,car_id); -- 普通的组合索引    create unique index index_phone_car_id on student(phone,car_id); -- 唯一的组合索引    删除索引    drop index 索引名 on 表名;    alert table 表名 drop index 索引名;eg:    ① select * from student where car_id='130825';    ② select * from student where phone='1523151';    ③ select * from student where phone='1523151' and car_id='130825';    ④ select * from student where car_id='130825' and phone='1523151';四条sql只有②、③、④能使用到索引index_phone_car_id,因为条件里面必须包含索引前面的字段,才能够进行匹配;而③、④相比where条件的顺序不一样,为什么④可以用到索引呢?因为mysql本身就是一层sql优化,他会根据sql来识别出该用哪个索引,我们可以理解为③、④在mysql眼中是等价的.全文索引全文索引的关键字是fulltext全文索引主要用来查找文本中的关键字,而不是直接与索引中的值相比较,它更像是一个搜索引擎,基于相似度的查询,而不是简单的where语句的参数匹配.用 like + % 就可以实现模糊匹配了,为什么还要全文索引?like + % 在文本比较少是合适的,但是对于大量的文本数据检索,是不可想象的,全文索引在大量的数据面前,能比like + %快N倍,速度不是一个数量级的,但是全文索引可能存在精度问题.-- 修改表结构添加全文索引alter table 表名 add fulltext 索引名(列名)-- 添加全文索引create fulltext index 索引名 on 表名(列名)-- 使用全文索引select * from 表名 where match(列名) against('yo');空间索引mysql在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型空间索引是对空间数据类型的字段建立的索引,mysql中的空间数据类型有四种,分别是GEOMETRY,POINT,LINESTRING,POLYGONMYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引创建空间索引的列,必须将其声明为NOT NULL空间索引一般是用的比较少.类型    含义    说明GEOMETRY    空间数据    任何一种空间类型POINT    点    坐标值LINESTRING    线    有一系列点连接而成POLYGON    多边形    由多条线组成索引内部原理剖析一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上,这样的话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级.所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度.换句话,索引的结构组织要尽量减少查找过程中磁盘I/O的存取次数.索引内部原理-Hash算法索引内部原理-二叉树和二叉平衡树索引内部原理-BTREE树MyISAM存储引擎MyISAM引擎使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址.InnoDB存储引擎InnoDB的叶节点的data域存放的是数据,相比MyISAM效率高一些,但是比较占硬盘内存大小.索引的特点-- 优点    ① 大大加快数据的查询速度    ② 使用分组和排序进行数据查询时,可以显著减少查询时分组和排序的时间    ③ 创建唯一索引,能够保证数据库表中每一行数据的唯一性    ④ 在实现数据的参考完整性方面,可以加速表和表之间的连接-- 缺点    ① 创建索引和维护索引需要消耗时间,并且随着数据量的增加,时间也会增加.    ② 索引需要占据磁盘空间    ③ 对数据表中的数据进行增加,修改,删除时,索引也要动态的维护,降低了维护的速度索引的创建原则① 更新频繁的列不应该设置索引② 数据量小的表不要使用索引(毕竟总共2页的文档,还要目录?)③ 重复数据多的字段不应设为索引(比如 性别,只有男和女一般来说:重复的数据超过百分之15就不应该建索引)④ 首先应考虑对where和order by 和group by 涉及的列上建立索引MySQL的存储引擎数据库存储引擎是数据库底层软件组织,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据不同的储存引擎提供不同的存储机制、索引技巧、锁定水平等功能,现在许多不同的数据库管理系统都支持多种不同的数据引擎,MySQL的核心就是存储引擎用户可以根据不同的需求为数据表选择不同的存储引擎可以使用SHOW ENGINES 命令可以查看MySQL的所有执行引擎我们可以看到默认的执行引擎是innoDB支持事务,行级锁定和外键.MySQL存储引擎的操作-- 查询当前数据库支持的存储引擎    show engines;-- 查看当前的默认存储引擎    show variables like '%storage_engines%';-- 查看某个表用了什么引擎(在现实结果里参数engine后面的就表示该表当前用的存储引擎)    show create table student;-- 创建表时指定存储引擎    create table(...) engine=MyISAM;-- 修改数据库引擎    alter table student engine=InnoDB;    alter table student engine=MyISAM;-- 修改MySQL默认存储引擎方法    ① 关闭mysql服务    ② 找到mysql安装目录下的my.ini文件    ③ 找到default-storage-engine = InnoDB 改为目标引擎    ④ 启动mysql服务原文链接:https://blog.csdn.net/qq_44590469/article/details/124818761
  • [行业资讯] 面试突击:MySQL 常用引擎有哪些?
    MySQL 有很多存储引擎(也叫数据引擎),所谓的存储引擎是指用于存储、处理和保护数据的核心服务。也就是存储引擎是数据库的底层软件组织。在 MySQL 中可以使用“show engines”来查询数据库的所有存储引擎,如下图所示:在上述列表中,我们最常用的存储引擎有以下 3 种:InnoDBMyISAMMEMORY下面我们分别来看。1.InnoDBInnoDB 是 MySQL 5.1 之后默认的存储引擎,它支持事务、支持外键、支持崩溃修复和自增列。如果对业务的完整性要求较高,比如张三给李四转账,需要减张三的钱,同时给李四加钱,这时候只能全部执行成功或全部执行失败,此时可以通过 InnoDB 来控制事务的提交和回滚,从而保证业务的完整性。优缺点分析InnoDB 的优势是支持事务、支持外键、支持崩溃修复和自增列;它的缺点是读写效率较差、占用的数据空间较大。2.MyISAMMyISAM 是 MySQL 5.1 之前默认的数据库引擎,读取效率较高,占用数据空间较少,但不支持事务、不支持行级锁、不支持外键等特性。因为不支持行级锁,因此在添加和修改操作时,会执行锁表操作,所以它的写入效率较低。优缺点分析MyISAM 引擎保存了单独的索引文件 .myi,且它的索引是直接定位到 OFFSET 的,而 InnoDB 没有单独的物理索引存储文件,且 InnoDB 索引寻址是先定位到块数据,再定位到行数据,所以 MyISAM 的查询效率是比 InnoDB 的查询效率要高。但它不支持事务、不支持外键,所以它的适用场景是读多写少,且对完整性要求不高的业务场景。3.MEMORY内存型数据库引擎,所有的数据都存储在内存中,因此它的读写效率很高,但 MySQL 服务重启之后数据会丢失。它同样不支持事务、不支持外键。MEMORY 支持 Hash 索引或 B 树索引,其中 Hash 索引是基于 key 查询的,因此查询效率特别高,但如果是基于范围查询的效率就比较低了。而前面两种存储引擎是基于 B+ 树的数据结构实现了。优缺点分析MEMORY 读写性能很高,但 MySQL 服务重启之后数据会丢失,它不支持事务和外键。适用场景是读写效率要求高,但对数据丢失不敏感的业务场景。4.查看和设置存储引擎4.1 查看存储引擎存储引擎的设置粒度是表级别的,也就是每张表可以设置不同的存储引擎,我们可以使用以下命令来查询某张表的存储引擎:如下图所示:4.2 设置存储引擎在创建一张表的时候设置存储引擎:修改一张已经存在表的存储引擎:总结MySQL 中最常见的存储引擎有:InnoDB、MyISAM 和 MEMORY,其中 InnoDB 是 MySQL 5.1 之后默认的存储引擎,它支持事务、支持外键、支持崩溃修复和自增列,它的特点是稳定(能保证业务的完整性),但数据的读写效率一般;而 MyISAM 的查询效率较高,但不支持事务和外键;MEMORY 的读写效率最高,但因为数据都保存在内存中的,所以 MySQL 服务重启之后数据就会丢失,因此它只适用于数据丢失不敏感的业务场景。
  • [交流吐槽] 光知道分库分表可不敢直接去面试,分表后读扩散怎么解决才是重点
    分库分表大家可能听得多了,但 读扩散 问题大家了解吗?这里涉及到几个问题。分库分表是什么?读扩散问题是什么?分库分表为什么会引发读扩散问题?怎么解决读扩散问题?这些问题还是比较有意思的。相信兄弟们也一定有机会遇到哈哈哈。我们先从分库分表的话题聊起吧。分库分表我们平时做项目开发。一开始,通常都先用一张数据表,而一般来说数据表写到2kw条数据之后,底层B+树的层级结构就可能会变高,不同层级的数据页一般都放在磁盘里不同的地方,换言之,磁盘IO就会增多,带来的便是查询性能变差。 如果对上面这句话有疑惑的话,可以去看下我之前写的文章。于是,当我们单表需要管理的数据变得越来越多,就不得不考虑数据库 分表 。而这里的分表,分为 水平分表和垂直分表 。垂直分表的原理比较简单,一般就是把某几列拆成一个新表,这样单行数据就会变小,B+树里的单个数据页(固定16kb)内能放入的行数就会变多,从而使单表能放入更多的数据。垂直分表没有太多可以说的点。下面,我们重点说说最常见的 水平分表 。水平分表有好几种做法,但不管是哪种,本质上都是将原来的 user 表,变成 user_0, user1, user2 .... uerN 这样的N多张小表。从读写一张user 大表 ,变成读写 user_1 … userN 这样的N张 小表 。每一张小表里,只保存一部分数据,但具体保存多少,这个自己定,一般就订个 500w~2kw 。那分表具体怎么做?根据id范围分表我认为最好用的,是根据id范围进行分表。我们假设每张分表能放 2kw 行数据。那user0就放主键id为 1~2kw 的数据。user1就放id为 2kw+1 ~ 4kw ,user2就放id为 4kw+1 ~ 6kw , userN就放 2N kw+1 ~ 2(N+1)kw 。根据id范围分表假设现在有条数据,id=3kw,将这个 3kw除2kw = 1.5 ,向下取整得到 1 ,那就可以得到这条数据属于 user1表 。于是去读写user1表就行了。这就完成了数据的路由逻辑,我们把这部分逻辑封装起来,放在数据库和业务代码之间。这样。 对于业务代码来说 ,它只知道自己在读写一张 user 表,根本不知道底下还分了那么多张小表。对于数据库来说,它并不知道自己被分表了,它只知道有那么几张表,正好名字长得比较像而已。这还只是在 一个数据库 里做分表,如果范围再搞大点,还能在 多个数据库 里做分表,这就是所谓的 分库分表 。不管是单库分表还是分库分表,都可以通过这样一个中间层逻辑做路由。还真的就应了那句话,没有什么是加中间层不能解决的。如果有,就多加一层。至于这个中间层的实现方式就更灵活了,它既可以像 第三方orm库 那样加在业务代码中。通过orm读写分表也可以在mysql和业务代码之间加个 proxy服务 。如果是通过第三方orm库的方式来做的话,那需要根据不同语言实现不同的代码库,所以不少厂都选择后者加个proxy的方式,这样就不需要关心上游服务用的是什么语言。通过proxy管理分表根据id取模分表这时候就有兄弟要提出问题了,"我看很多方案都 对id取模 ,你这个方案是不是不完整?"。取模的方案也是很常见的。比如一个id=31进来,我们一共分了5张表,分别是user0到user4。对 31%5=1 ,取模得 1 ,于是就能知道应该读写 user1 表。根据id取模分表优点当然是比较简单。而且读写数据都可以很均匀的分摊到每个分表上。但 缺点 也比较明显,如果想要扩展表的个数,比如从5张表变成8张表。那同样还是id=31的数据, 31%8 = 7 ,就需要读写user7这张表。跟原来就对不上了。这就需要考虑 数据迁移 的问题。很头秃。为了避免后续扩展的问题,我见过一些业务一开始就将数据预估得很大,然后心一横,分成100张表,一张表如果存个2kw条,那也能存20亿数据了。也不是说这样不行吧,就是这个业务直到最后放弃的时候,也就存了百万条数据,每次打开数据库表能看到茫茫多的user_xx,就是不太舒服,专业点,叫增加了程序员的 心智负担 。而上面一种方式,根据id范围去分表,就能很好的解决这些问题,数据少的时候,表也少,随着数据增多,表会慢慢变多。而且这样表还可以无限扩展。那是不是说取模的做法就用不上了呢?也不是。将上面两种方式结合起来id取模的做法,最大的好处是,新写入的数据都是实实在在的分散到了 多张表 上。而根据id范围去做分表,因为id是递增的,那新写入的数据一般都会落到 某一张表 上,如果你的业务场景写数据特别频繁,那这张表就会出现 写热点 的问题。这时候就可以将id取模和id范围分表的方式结合起来。我们可以在某个id范围里,引入取模的功能。比如 以前 2kw~4kw 是user1表,现在可以在这个范围 再分成5个表 ,也就是引入user1-0, user1-2到user1-4,在这5个表里取模。举个例子,id=3kw,根据范围,会分到user1表,然后再进行取模 3kw % 5 = 0,也就是读写user1-0表。这样就可以将写单表分摊为写多表。这在分库的场景下优势会更明显,不同的库,可以把服务部署到不同的机器上,这样各个机器的性能都能被用起来。根据id范围分表后再取模读扩散问题我们上面提到的好几种分表方式,都用了id这一列作为 分表的依据 ,这其实就是所谓的 分片键 。实际上我们一般也是用的 数据库主键 作为 分片键 。这样,理想情况下我们已知一个id,不管是根据哪种规则,我们都能很快定位到该读哪个分表。但很多情况下,我们的查询又不是只查主键,如果我的数据库表有一列name,并且加了个普通索引。这样我执行下面的sqlselect * from user where name = "小白";由于name并不是分片键,我们没法定位到具体要到哪个分表上去执行sql。于是就会对 所有分表 都执行上面的sql,当然不会是串行执行sql,一般都是 并发 执行sql的。如果我有100张表,就执行100次sql。如果我有200张表,就执行200次sql。随着我的表越来越多,次数会越来越多,这就是所谓的 读扩散问题 。读扩散问题这是个比较有趣的问题,它确实是个问题,但大部分的业务不会去处理它,读100次怎么了,数据增长之后读的次数会不断增加又怎么了?但架不住我的 业务不赚钱 啊,也根本 长不了那么多数据 啊。话是这么说没错,但面试官问你的时候,你得知道怎么处理啊。引入新表来做分表问题的核心在于,主键是分片键,而普通索引列并不分片。那好办,我们单独建个 新的分片表 ,这个新表里的列就只有旧表的主键id和普通索引列,而这次换普通索引列来做分片键。通过新索引表解决读扩散问题这样当我们要查询普通索引列时,先到这个新的分片表里做一次查询,就能迅速定位到对应的主键id,然后再拿主键id去旧的分片表里查一次数据。这样就从原来漫无目的的全表扩散查询,缩减为只查固定几个表了。举个例子。比如我的表原本长下面这样,其中id列是主键,同时也是分片键,name列是非主键索引。为了简化,假设三条数据一张表。此时分表里 id=1,4,6 的都有 name="小白" 的数据。当我们执行 select * from user where name = "小白"; 则需要并发查3张表,随着表变多,查询次数会变得更多。举例说明读扩散问题但如果我们为name列 建个新表(nameX),以name为新的分片键 。这样我们可以先执行 select id from nameX where name = "小白";再拿着结果里的ids去查询 select * from user where id in (ids); 这样就算表变多了,也可以迅速定位到某几张具体的表,减少了查询次数。举例说明通过新索引表解决读扩散问题但这个做法的缺点也比较明显,你需要维护两套表,并且普通索引列更新时,要两张表同时进行更改。有一定的开发量有没有更简单的方案?使用其他更合适的存储我们常规的查询是通过id主键去查询对应的name列。而像上面的方案,则通过引入一个新表, 倒过来 ,先用name查到对应的id,再拿id去获取具体的数据。这其实就像是建立了一个新的索引一样,像这种,通过name列反查原数据的思想,其实就很类似于 倒排索引 。相当于我们是利用了倒排索引的思路去解决分表下的数据查询问题。回想下,其实我们的 原始需求 无非就是在大量数据的场景下依然能提供普通索引列或其他更多维度的查询。这种场合,更适合使用es,es天然分片,而且内部利用 倒排索引 的形式来加速数据查询。哦?兄弟萌,又是它, 倒排索引 ,又是个极小的细节,做好笔记。举个例子,我同样是一行数据 id,name,age。在mysql里,你得根据id分片,如果要支持name和age的查询,为了防止读扩散,你得分别再建一个name的分片表和一个age的分片表。而如果你用es,它会在它内部以id分片键进行分片,同时还能建一个name到id,和一个age到id的倒排索引。这是不是就跟上面做的事情没啥区别。而且将mysql接入es也非常简单,我们可以通过开源工具 canal 监听mysql的 binlog 日志变更,再将数据解析后写入es,这样es就能提供 近实时 的查询能力。mysql同步es觉得es+mysql还是繁琐?有没有其他更简洁的方案?有。别用mysql了,改用 tidb 吧,相信大家多少也听说过这个名称,这是个 分布式数据库 。它通过引入 Range 的概念进行数据表分片,比如第一个分片表的id在0~2kw,第二个分片表的id在2kw~4kw。哦?有没有很熟悉,这不就是文章开头提到的根据id范围进行数据库分表吗?它支持普通索引,并且普通索引也是分片的,这是不是又跟上面提到的倒排索引方案很类似。又是个极小的细节。并且tidb跟mysql的语法几乎一致,现在也有非常多现成的工具可以帮你把数据从mysql迁移到tidb。所以开发成本并不高。总结mysql在单表数据过大时,查询性能会变差,因此当数据量变得巨大时,需要考虑水平分表。水平分表需要选定一个分片键,一般选择主键,然后根据id进行取模,或者根据id的范围进行分表。mysql水平分表后,对于非分片键字段的查询会有读扩散的问题,可以用普通索引列作分片键建一个新表,先查新表拿到id后再回到原表再查一次原表。这本质上是借鉴了倒排索引的思路。如果想要支持更多维度的查询,可以监听mysql的binlog,将数据写入到es,提供近实时的查询能力。当然,用tidb替换mysql也是个思路。tidb属实是个好东西,不少厂都拿它换个皮贴个标,做成自己的 自研数据库 ,非常推荐大家学习一波。不要做过早的优化,没事别上来就分100个表,很多时候真用不上。参考资料《图解分库分表》https://mp.weixin.qq.com/s/OI5y4HMTuEZR1hoz9aOMxg最后当年我还在某个游戏项目组里做开发的时候,从企鹅那边挖来的策划信誓旦旦的说,我们要做的这款游戏老少皆宜,肯定是爆款。要做成全球同服。上线至少 过亿注册 , 十万人同时在线 。要好好规划和设计。我们算了下,信他能有个1亿注册。用了id范围的方式进行分片,分了 4张表 。搞得我热血沸腾。那天晚上下班,夏蝉鸣泣,从赤道吹来的热风阵阵拂过我的手臂,我听着泽野弘之的歌,就算是开电瓶车,我都感觉自己像是在开高达。一年后。游戏上线前一天通知运维加机器,怕顶不住,要整夜关注。后来上线了,全球最高在线人数 58 人。其中有 7 个是项目组成员。还是夏天,还是同样的下班路,想哭,但我不能哭,因为骑电瓶车的时候擦眼泪不安全。
  • [知识分享] 基于云服务MRS构建DolphinScheduler2调度系统
    >摘要:本文介绍如何搭建DolphinScheduler并运行MRS作业。 本文分享自华为云社区《[基于云服务MRS构建DolphinScheduler2调度系统](https://bbs.huaweicloud.com/blogs/355194?utm_source=csdn&utm_medium=bbs-ex&utm_campaign=ei&utm_content=content)》,作者: 啊喔YeYe 。 # 为什么写这篇文章? 1. 网上关于DolphinScheduler的介绍很多但是都缺少了与实际大数据平台结合的案例指导。 2. DolphinScheduler1.x版本,2.x重构了内核实现,性能提升20倍!但是因为重构导致2.x与1.x部署过程存在差异,按照1.x部署2.x版本存在不少坑。 3. 选择轻量化、免运维、低成本的大数据云服务是业界趋势,如果搭建DolphinScheduler再同步自建一套Hadoop生态成本太高!因此我们通过结合华为云MRS服务构建数据中台。 # 环境准备 - dolphinscheduler2.0.3安装包 - MRS 3.1.0普通集群 - Mysql安装包 5.7.35 - ECS centos7.6 # 安装MRS 客户端 MRS客户端提供java、python开发环境,也提供开通集群中各组件的环境变量:Hadoop、hive、hbase、flink等。 参见登录ECS安装集群外客户端 # 安装MySQL服务 ## 1. 创建ECS用户 为了方便数据库管理,对于安装的MySQL数据库,生产上建立了一个mysql用户和mysql用户组: ``` # 添加mysql用户组 groupadd mysql # 添加mysql用户 useradd -g mysql mysql -d /home/mysql # 修改mysql用户的登陆密码 passwd **** ``` ## 2.解压安装包 ``` cd /usr/local/ tar -xzvf mysql-5.7.13-linux-glibc2.5-x86_64.tar.gz # 改名为mysql mv mysql-5.7.13-linux-glibc2.5-x86_64 mysql ``` 赋予用户读写权限 chown -R mysql:mysql mysql/ ## 3. 配置文件初始化 ### 1. 创建配置文件my.cnf ``` vim /etc/my.cnf [client] port = 3306 socket = /tmp/mysql.sock [mysqld] character_set_server=utf8 init_connect='SET NAMES utf8' basedir=/usr/local/mysql datadir=/usr/local/mysql/data socket=/tmp/mysql.sock log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid #不区分大小写 lower_case_table_names = 1 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION max_connections=5000 default-time_zone = '+8:00' ``` ### 2. 初始化log文件,防止没有权限 ``` #手动编辑一下日志文件,什么也不用写,直接保存退出 cd /var/log/ vim mysqld.log :wq 退出保存 chmod 777 mysqld.log chown mysql:mysql mysqld.log ``` ### 3. 初始化pid文件,防止没有权限 ``` cd /var/run/ mkdir mysqld cd mysqld vi mysqld.pid :wq保存退出 # 赋权 cd .. chmod 777 mysqld chown -R mysql:mysql /mysqld ``` ## 4. 初始化数据库 初始化数据库,并指定启动mysql的用户,否则就会在启动MySQL时出现权限不足的问题 ``` /usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --lc_messages_dir=/usr/local/mysql/share --lc_messages=en_US ``` 初始化完成后,在my.cnf中配置的datadir目录(/var/log/mysqld.log)下生成一个error.log文件,里面记录了root用户的随机密码。 cat /var/log/mysqld.log 执行后记录最后一行:root@localhost: xxxxx 。 这里的xxxxx就是初始密码。后面登入数据库要用到。 # 4. 启动数据库 ``` #源目录启动: /usr/local/mysql/support-files/mysql.server start ``` 设置开机自启动服务 ``` # 复制启动脚本到资源目录 cp /usr/local/mysql/support-files/mysql.server /etc/rc.d/init.d/mysqld # 增加mysqld服务控制脚本执行权限 chmod +x /etc/rc.d/init.d/mysqld # 将mysqld服务加入到系统服务 chkconfig --add mysqld # 检查mysqld服务是否已经生效 chkconfig --list mysqld # 切换至mysql用户,启动mysql,或者稍后下一步再启动。 service mysqld start # 从此就可以使用service mysqld命令启动/停止服务 su mysql service mysqld start service mysqld stop service mysqld restart ``` # 5.登陆,修改密码,预置dolphinscheduler的用户 **1. 修改密码** ``` # 系统默认会查找/usr/bin下的命令;建立一个链接文件。 ln -s /usr/local/mysql/bin/mysql /usr/bin # 登陆mysql的root用户 mysql -uroot -p # 输入上面的默认初始密码(root@localhost: xxxxx) # 修改root用户密码为XXXXXX set password for root@localhost=password("XXXXXX"); ``` **2. 预置dolphinscheduler的用户** ``` mysql -uroot -p mysql>CREATE DATABASE dolphinscheduler DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; # 修改 {user} 和 {password} 为你希望的用户名和密码,192.168.56.201是我的主机ID mysql> GRANT ALL PRIVILEGES ON dolphinscheduler.* TO 'dolphinscheduler'@'%' IDENTIFIED BY 'dolphinscheduler'; mysql> GRANT ALL PRIVILEGES ON dolphinscheduler.* TO 'dolphinscheduler'@'localhost' IDENTIFIED BY 'dolphinscheduler'; mysql> GRANT ALL PRIVILEGES ON dolphinscheduler.* TO 'dolphinscheduler'@'192.168.56.201' IDENTIFIED BY 'dolphinscheduler'; #刷新权限 mysql> flush privileges; #检查是否创建用户成功 mysql> show databases; #出现dolphinscheduler,查看创建的用户 mysql> use mysql; mysql> select User,authentication_string,Host from user; ``` # 安装dolphinscheduler服务 **1. 建立本机id免密** 在任意文件夹下进行这一步均可,为防止误会,我在dolphinscheduler203进行这一步,创建用户dolphinscheduler,后面所有操作都是再这个用户下做的。设置root免密登录该用户: ``` # 创建用户需使用 root 登录 useradd dolphinscheduler # 添加密码 echo "dolphinscheduler" | passwd --stdin dolphinscheduler # 配置 sudo 免密 sed -i '$adolphinscheduler ALL=(ALL) NOPASSWD: NOPASSWD: ALL' /etc/sudoers sed -i 's/Defaults requirett/#Defaults requirett/g' /etc/sudoers # 修改目录权限,在这一步前将jdbcDriver(我的mysql版本5.6.1,driver版本8.0.16)放入lib里,一并修改权限 chown -R dolphinscheduler:dolphinscheduler dolphinscheduler203 #进入新用户 su dolphinscheduler ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys ``` **2. 修改配置参数** 修改install-config.conf文件 ``` [dolphinscheduler@km1 dolphinscheduler203]$ vi conf/config/install-config.conf 修改: ips="192.168.56.201" masters="192.168.56.201" workers="192.168.56.201:default" alertServer="192.168.56.201" apiServers="192.168.56.201" pythonGatewayServers="192.168.56.201" # DolphinScheduler安装路径,如果不存在会创建,这里不能放你解压后的ds路径,放置后在运行代码时同名文件、文件夹会冲突导致消失 installPath="/opt/dolphinscheduler203" # 部署用户,填写在 **配置用户免密及权限** 中创建的用户 deployUser="dolphinscheduler" # --------------------------------------------------------- # DolphinScheduler ENV # --------------------------------------------------------- # 安装的JDK中 JAVA_HOME 所在的位置 javaHome="/opt/hadoopclient/JDK/jdk1.8.0_272" # --------------------------------------------------------- # Database # --------------------------------------------------------- # 数据库的类型,用户名,密码,IP,端口,元数据库db。其中 DATABASE_TYPE 目前支持 mysql, postgresql, H2 # 请确保配置的值使用双引号引用,否则配置可能不生效 DATABASE_TYPE="mysql" SPRING_DATASOURCE_URL="jdbc:mysql://192.168.56.201:3306/dolphinscheduler?useUnicode=true&characterEncoding=UTF-8" # 如果你不是以 dolphinscheduler/dolphinscheduler 作为用户名和密码的,需要进行修改 SPRING_DATASOURCE_USERNAME="dolphinscheduler" SPRING_DATASOURCE_PASSWORD="dolphinscheduler" # --------------------------------------------------------- # Registry Server # --------------------------------------------------------- # 注册中心地址,zookeeper服务的地址 registryServers="192.168.56.201:2181" ``` zk地址获取方式: 登录manager,访问zookeeper服务,copy管理ip即可(前提ECS与MRS集群网络已打通): ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133576612207353.png) **2. 修改 conf/env 目录下的 dolphinscheduler_env.sh** 以相关用到的软件都安装在/opt/Bigdata/client下为例: ``` • export HADOOP_HOME=/opt/Bigdata/client/HDFS/Hadoop • export HADOOP_CONF_DIR=/opt/Bigdata/client/HDFS/Hadoop • export SPARK_HOME2=/opt/Bigdata/client/Spark2x/spark • export PYTHON_HOME=/usr/bin/pytho • export JAVA_HOME=/opt/Bigdata/client/JDK/jdk1.8.0_272 • export HIVE_HOME=/opt/Bigdata/client/Hive/Beeline • export FLINK_HOME=/opt/Bigdata/client/Flink/flink • export DATAX_HOME=/xxx/datax/bin/datax.py • export PATH=$HADOOP_HOME/bin:$SPARK_HOME2/bin:$PYTHON_HOME:$JAVA_HOME/bin:$HIVE_HOME/bin:$PATH:$FLINK_HOME/bin:$DATAX_HOME:$PATH ``` **说明** 这一步非常重要,例如 JAVA_HOME 和 PATH 是必须要配置的,没有用到的可以忽略或者注释掉 环境变量查找方式说明:假设MRS客户端安装在/opt/Bigdata/client ``` source /opt/client/bigdata_env HADOOP_HOME环境地址:通过echo $HADOOP_HOME获得 /opt/Bigdata/client/HDFS/Hadoop HADOOP_CONF_DIR:/opt/Bigdata/client/HDFS/Hadoop SPARK_HOME: 通过echo $SPARK_HOME获得/opt/Bigdata/client/Spark2x/spark JAVA_HOME: 通过echo $JAVA_HOME获得/opt/Bigdata/client/JDK/jdk1.8.0_272 HIVE_HOME:通过echo $HIVE_HOME获得/opt/Bigdata/client/Hive/Beeline FLINK_HOME:通过echo $FLINK_HOME 获得/opt/Bigdata/client/Flink/flink ``` **3. 将mysql 驱动包放入lib下** ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133621101450379.png) ``` tar -zxvf mysql-connector-java-5.1.47.tar.gz ``` ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133631910359480.png) ``` cp mysql-connector-java-5.1.47.jar /opt/dolphinscheduler203/lib/ ``` **4.创建元数据库数据表** 执行sh script/create-dolphinscheduler.sh **5. 服务安装、启停** 每次启停都可以重新部署一次:sh install.sh # 启停命令 ``` # 一键停止集群所有服务 sh ./bin/stop-all.sh # 一键开启集群所有服务 sh ./bin/start-all.sh # 启停 Master sh ./bin/dolphinscheduler-daemon.sh stop master-server sh ./bin/dolphinscheduler-daemon.sh start master-server # 启停 Worker sh ./bin/dolphinscheduler-daemon.sh start worker-server sh ./bin/dolphinscheduler-daemon.sh stop worker-server # 启停 Api sh ./bin/dolphinscheduler-daemon.sh start api-server sh ./bin/dolphinscheduler-daemon.sh stop api-server # 启停 Logger sh ./bin/dolphinscheduler-daemon.sh start logger-server sh ./bin/dolphinscheduler-daemon.sh stop logger-server # 启停 Alert sh ./bin/dolphinscheduler-daemon.sh start alert-server sh ./bin/dolphinscheduler-daemon.sh stop alert-server # 启停 Python Gateway sh ./bin/dolphinscheduler-daemon.sh start python-gateway-server sh ./bin/dolphinscheduler-daemon.sh stop python-gateway-server ``` # 6. 登录系统 访问前端页面地址:http://xxx:12345/dolphinscheduler 用户名密码:admin/dolphinscheduler123 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133680031334513.png) # 提交MRS任务 ## 1.登录进入dolphinscheduler webui ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133700613528376.png) ## 2. 配置MRS-hive连接 登录mrs manager查看hiveserver ip: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133712536337444.png) 创建Hive数据连接,普通集群没有权限可以使用默认用户hive,如有需要可以使用在MRS里面已经创建的用户: ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133721059767204.png) ## 3. 创建任务 1、创建项目 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133734699156508.png) 2、创建工作流 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133754452224620.png) 3、在工作流编辑任务 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133762457725059.png) 4、任务上线 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133768968925033.png) 5、启动任务流之后可以查询工作流实例和任务实例 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133776277689121.png) ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133786553699823.png) 6、登录Manager页面,选择“集群 > 服务 > Yarn > 概览” 7、单击“ResourceManager WebUI”后面对应的链接,进入Yarn的WebUI页面,查看Spark任务是否运行 ![image.png](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20226/2/1654133797822703249.png)
  • [交流吐槽] 原来 MySQL 索引要这么设计才能起飞
    引言相信大家都知道索引可以加快数据的查询速度,但是有时候如果索引设计不当,也可能造成索引失效而进行全表数据扫描,从而最终导致系统性能下降。因此我们在索引设计阶段就需要充分考虑各种可能情况,尽量避免由于索引设计缺陷导致的后期出现数据查询性能问题。本文总结了7个实用Mysql索引设计原则,相信在大家进行索引设计的时候可以进行参考。索引设计原则我们在数据库表设计好之后,先不要着急马上就进行表的索引设计,因为这个时候其实你也并不清楚未来在这个表上可能存在的查询条件到底是什么。所以我们需要先根据实际的产品需求来进行业务代码开发,在这个过程中我们必然会涉及到数据库持久化操作,也就是我们常说的CRUD。等我们把对应的Mapper接口以及SQL写好后,也就基本确定了哪些字段是条件字段、哪些字段是排序字段以及哪些字段是分组字段。这些字段确认好之后,我们就可以着手进行数据库表的索引设计了。关于如何设计索引,这里给大家梳理了7条非常实用的索引设计原则,相信大家在实际的项目中都可以用得上。原则一:根据SQL语句中的where条件、order by条件以及group by条件对应的字段进行索引设计。当我们的SQL语句中出现where条件、order by条件以及group by条件的时候,也就是表示我们需要通过SQL语句来进行数据过滤(where条件)、根据哪些字段进行排序(order by条件)以及根据哪些字段进行分组聚合(group by条件)。因此我们的设计的索引需要尽可能的覆盖这些字段,为的就是在数据查询的时候通过这些字段用上索引。假设我们有这样一张表clothes可以用来查询衣服,那么在设计索引的时候就需要根据实际的查询需求在对应的字段建立索引。那么对于衣服这张表来说一般会在c_brand(品牌)、c_type(类型)以及c_size(尺码)等这些字段建立索引,因为他们是最常用的筛选条件,另外可以考虑在价格字段上进行排序,这也是非常常见的过滤条件。原则二:在基数比较大的字段上建立索引,同时需要将基数更高的字段放在最左边。什么叫基数比较大的字段呢?实际就是值比较多的字段,或者说就是字段值的区分度比较高,我们可以用一个简单的公式来评判某个字段的区分度,区分度等于count(distinct 具体的列) / count(*),表示字段不重复的比例。也就是说字段中包含的变化数据比较多的话是比较适合建索引的,因为这样才能发挥索引B+树的潜力。为什么这么说呢?假设有这样一张员工表中包含了性别字段i_gender,它的值只有0:男性,1:女性这两个值。我们都知道Mysql的索引结构是通过B+树实现的,而B+树背后的核心本质思想实际就是二分查找。而二分查找就需要待排序的数据基数大,也就是区分度高。而字段中只有0、1这样的就属于基数比较小,无法发挥索引树检索的效率,Mysql认为这种索引树还不如全表查询来的痛快。另外还需要特别注意点是,对于区分度高的字段我们应该把它放在联合索引的左侧,因为这样可以更快得过滤掉更多的无效数据,从而提升索引的使用效率。还是拿员工信息来举例子,员工表中的毕业院校的字段的区分度就比民族字段区分度要高的多,索引我们在设计联合索引的时候就需要将毕业院校的字段仿造民族的左侧,这样可以更快的过滤掉无效数据。原则三:如果SQL中出现JOIN操作,那么JOIN的字段必须建立索引,同时字段的类型、字符集都需要保持一致。数据库JOIN是常见的数据记录遍历的SQL操作,假设平台有一张用户表以及订单表,这个时候如果想要获取用户的订单信息,那么就可以使用JOIN操作来完成操作。不过在使用JOIN的过程中如果参与JOIN的表过多的话,对应的结果可能是一个笛卡尔积,对于Mysql的优化器来说实在是很难选择出来哪个才是最好的执行计划,就好比找对象一样,如果只有一个可以选择也没什么好纠结的,如果有10个可以选择,那就很头大了,不知道选择哪个好,因此我们要避免出现过多数量表的JOIN。另外很重要的一点就是在进行JOIN的字段上一定要建立索引,否则全表扫描。同时JOIN字段的类型、字符集等都要保持一致,避免在JOIN过程中可能导致的隐式的类型转换造成不走索引的后果。原则四:如果SQL中出现JOIN操作,那么JOIN的字段必须建立索引,同时字段的类型、字符集都需要保持一致。数据库JOIN是常见的数据记录遍历的SQL操作,假设平台有一张用户表以及订单表,这个时候如果想要获取用户的订单信息,那么就可以使用JOIN操作来完成操作。不过在使用JOIN的过程中如果参与JOIN的表过多的话,对应的结果可能是一个笛卡尔积,对于Mysql的优化器来说实在是很难选择出来哪个才是最好的执行计划,就好比找对象一样,如果只有一个可以选择也没什么好纠结的,如果有10个可以选择,那就很头大了,不知道选择哪个好,因此我们要避免出现过多数量表的JOIN。另外很重要的一点就是在进行JOIN的字段上一定要建立索引,否则全表扫描。还有很重要的一点,用于JOIN的字段的类型、字符集等都需要保持一致,否则可能存在隐式的类型转换导致走不了索引。原则五:尽量在字段类型值比较小的字段上建立索引。索引本身也是占用磁盘空间的,因此如果可以在字段类型比较小的字段上面建立索引,相应的索引占用空间就会更少,对应其数据检索的效率就会更高。但是这并非绝对的,如果存在区分度更高的字段但是字段类型比较大,那么我们还是会在区分度高的字段上面建立索引,但是我们可以采取一些折中的办法,比如我们可以取字段的前10个字符作为索引,这样我们们既可以在区分度高的字段建立索引,但是又至于太占用磁盘空间。原则六:索引不是建地越多越好有的同学在设计索引的时候恨不得把所有的字段都加上索引,总是觉得索引越多肯定性能越好,实际上真实场景下并非如此。我们都知道索引就像是一本书的目录,就像树的目录会占用书中的纸张一样,索引也是需要占用磁盘空间进行存储的,因此过多的索引会浪费资源。另外索引过多反而会降低性能,因为在进行数据插入的过程中,如果索引建立的过多就会导致更新多棵索引树,在这个过程中,如果数据的插入并不是按照顺序插入那么还会导致数据页分裂的问题。因此我们尽量通过两道三个联合索引来覆盖全部的查询场景。原则七:使用字符串前缀创建索引有些字段类型的长度比较长,因此字段的区分区相对来说也是比较大的,因此这些字段比较适合建索引。但是也是因为字段长度的原因,所建立的索引占用磁盘空间就会相对较大。实际上只要字段区分度足够高,没有必要对全字段建立索引,我们可以截取字段指定数量的字符作为检索条件的索引,具体需要截取多少字符那需要根据截取的字符串是否可以保持比较大区分度来进行决定。总结本文主要总结了在进行索引设计的时候需要考虑的几点设计原则,其实索引设计的根本无非就是两点,一个是希望通过两三个联合索引来覆盖数据检索的各个场景,避免因为检索的时候没有索引导致的数据检索效率低的问题,再者就是希望在实际的SQL运行过程中尽量避免索引失效情况的发生,避免建了索引但是实际上并不起作用。把握了这两个准则之后,相信大家在设计索引的时候可以游刃有余。
  • [行业资讯] MariaDB:真正的实时同步数据库,MySQL要小心了
    一、背景介绍无论是采用binlog或者GTID的方式,其本质都是通过I/O_thread和sql_thread的形式进行的同步,因为无法避免复制延迟而饱受诟病,基于上述MariaDB引入了Galera Cluster来解决此问题。二、Galera Cluster介绍Galera Cluster与传统的复制方式不同,不通过I/O_thread和sql_thread进行同步,而是在更底层通过wsrep实现文件系统级别的同步,可以做到几乎实时同步,而其上的MySQL对此一无所知这就要求MySQL能够调用wsrep提供的API来完成,在Mariadb10.1之前的版本,支持Galera Cluster的版本是与Mariadb分开发行的,其版本名称就成为Mariadb-Galera,Mariadb10.1以后的版本中MariaDB Galera Cluste不再单独发行,而是以galera-25.3.12-2.el7.x86_64包的形式出现方面都强过MySQL。MariaDB Galera Cluster主要功能同步复制:真正的multi-master,即所有节点可以同时读写数据库自动的节点成员控制,失效节点自动被清除新节点加入数据自动复制真正的并行复制,行级用户可以直接连接集群,使用感受上与MySQL完全一致MariaDB Galera Cluster的优缺点1.优势:因为是多主,所以不存在Slavelag(延迟)不存在丢失事务的情况同时具有读和写的扩展能力更小的客户端延迟节点间数据是同步的,而Master/Slave模式是异步的,不同slave上的binlog可能是不同的2.缺点:加入新节点时开销大,需要复制完整的数据不能有效地解决写扩展的问题,所有的写操作都发生在所有的节点有多少个节点,就有多少份重复的数据由于事务提交需要跨节点通信,即涉及分布式事务操作,因此写入会比主从复制慢很多,节点越多,写入越慢,死锁和回滚也会更加频繁对网络要求比较高,如果网络出现波动不稳定,则可能会造成两个节点失联,Galera Cluster集群会发生脑裂,服务将不可用还有一些地方存在局限:仅支持InnoDB/XtraDB存储引擎,任何写入其他引擎的表,包括mysql.*表都不会被复制。但是DDL语句可以复制,但是insert into mysql.user(MyISAM存储引擎)之类的插入数据不会被复制Delete操作不支持没有主键的表,因为没有主键的表在不同的节点上的顺序不同,如果执行select … limit …将出现不同的结果集LOCK/UNLOCK TABLES/FLUSH TABLES WITH READ LOCKS不支持单表所锁,以及锁函数GET_LOCK()、RELEASE_LOCK(),但FLUSH TABLES WITH READ LOCK支持全局表锁General Query Log日志不能保存在表中,如果开始查询日志,则只能保存到文件中不能有大事务写入,不能操作wsrep_max_ws_rows=131072(行),且写入集不能超过wsrep_max_ws_size=1073741824(1GB),否则客户端直接报错由于集群是乐观锁并发控制,因此,在commit阶段会有事务冲突发生。如果两个事务在集群中的不同节点上对同一行写入并提交,则失败的节点将回滚,客户端返回死锁报错XA分布式事务不支持Codership Galera Cluster,在提交时可能会回滚整个集群的写入吞吐量取决于最弱的节点限制,集群要使用同一的配置三、 MariaDB与Mysql的对比1.MariaDB发展趋势和更新频率毕竟基于MySQL创始人领衔开发的MariaDB数据库,肯定是知道MYSQL数据库存在的弱项,然后提供更好的兼容性和扩展性,我们基本上完全可以将MYSQL数据库建议到MariaDB数据库中,而且MariaDB发展速度和升级速度远远优先。2.MySQL封闭且发展缓慢由于MySQL在被收购之后更新速度与性能的优化非常的缓慢,而且是闭源的,完全没有Oracle之外的人参与进来,很多需要解决的问题都没有升级进去,反之很多公司虽然也有利用自己开发的分支Mysql版本。3.MariaDB的特点和优势MariaDB基于事务的Maria存储引擎,替换了MySQL的MyISAM存储引擎,它使用了Percona的 XtraDB,InnoDB的变体,MariaDB默认的存储引擎是Aria,不是MyISAM。Aria可以支持事务,但是默认情况下没有打开事务支持,因为事务支持对性能会有影响。MariaDB是一个采用Maria存储引擎的MySQL分支版本,是由原来 MySQL 的作者Michael Widenius创办的公司所开发的免费开源的数据库服务器。4.MariaDB与MySQL对比这个直观的区别在于MariaDB能够快速的查询和处理数据,且占用资源相对是少于MySQL数据库的,而且在运行速度、以及支持对 Unicode 的排序问题优于MYSQL数据库。
  • [交流吐槽] 吊打MySQL,MariaDB到底强在哪?
    MySQL 的发展史MySQL 的历史可以追溯到 1979 年,它的创始人叫作 Michael Widenius,他在开发一个报表工具的时候,设计了一套 API。后来他的客户要求他的 API 支持 sql 语句,他直接借助于 mSQL(当时比较牛)的代码,将它集成到自己的存储引擎中。但是他总是感觉不满意,萌生了要自己做一套数据库的想法。一到 1996 年,MySQL 1.0 发布,仅仅过了几个月的时间,1996 年 10 月 MySQL 3.11.1 当时发布了 Solaris 的版本,一个月后,Linux 的版本诞生,从那时候开始,MySQL 慢慢的被人所接受。1999 年,Michael Widenius 成立了 MySQL AB 公司,MySQL 由个人开发转变为团队开发,2000 年使用 GPL 协议开源。2001 年,MySQL 生命中的大事发生了,那就是存储引擎 InnoDB 的诞生!直到现在,MySQL 可以选择的存储引擎,InnoDB 依然是 NO.1。2008 年 1 月,MySQL AB 公司被 Sun 公司以 10 亿美金收购,MySQL 数据库进入 Sun 时代。Sun 为 MySQL 的发展提供了绝佳的环境,2008 年 11 月,MySQL 5.1 发布,MySQL 成为了最受欢迎的小型数据库。在此之前,Oracle 在 2005 年就收购了 InnoDB,因此,InnoDB 一直以来都只能作为第三方插件供用户选择。2009 年 4 月,Oracle 公司以 74 亿美元收购 Sun 公司,MySQL 也随之进入 Oracle 时代。2010 年 12 月,MySQL 5.5 发布,Oracle 终于把 InnoDB 做成了 MySQL 默认的存储引擎,MySQL 从此进入了辉煌时代。然而,从那之后,Oracle 对 MySQL 的态度渐渐发生了变化,Oracle 虽然宣称 MySQL 依然尊少 GPL 协议,但却暗地里把开发人员全部换成了 Oracle 自己人。开源社区再也影响不了 MySQL 发展的脚步,真正有心做贡献的人也被拒之门外,MySQL 随时都有闭源的可能……横空出世的 MariaDB 是什么鬼先提一下 MySQL 名字的由来吧,Michael Widenius 的女儿的简称就是 MY,Michael Widenius大 概也是把 MySQL 当成自己的女儿吧。看着自己辛苦养大的 MySQL 被 Oracle 搞成这样,Michael Widenius 非常失望,决定在 MySQL 走向闭源前,将 MySQL 进行分支化,依然是使用了自己女儿的名字 MariaDB(玛莉亚 DB)。MariaDB 数据库管理系统是 MySQL 的一个分支,主要由开源社区在维护,采用 GPL 授权许可 MariaDB 的目的是完全兼容 MySQL,包括 API 和命令行,使之能轻松成为 MySQL 的代替品。在存储引擎方面,使用 XtraDB 来代替 MySQL 的 InnoDB。MariaDB 由 MySQL 的创始人 Michael Widenius 主导,由开源社区的大神们进行开发。因此,大家都认为,MariaDB 拥有比 MySQL 更纯正的 MySQL 血脉。最初的版本更新与 MySQL 同步,相对 MySQL5 以后的版本,MariaDB 也有相应的 5.1~5.5 的版本。后来 MariaDB 终于摆脱了 MySQL,它的版本号直接从 10.0 开始,以自己的步伐进行开发,当然,还是可以对 MySQL 完全兼容。现在,MariaDB 的数据特性、性能等都超越了 MySQL。测试环境本性能测试环境如下:CPU:I7内存:8GOS:Windows 10 64位硬盘类型:SSDMySQL:8.0.19MariaDB:10.4.12分别在 MySQl 和 MariaDB 中创建名为 performance 的数据库,并创建 log 表,都使用 innodb 作为数据库引擎:CREATE TABLE `performance`.`log`(      `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,    `time` DATETIME NOT NULL,    `level` ENUM('info','debug','error') NOT NULL,    `message` TEXT NOT NULL,    PRIMARY KEY (`id`)  ) ENGINE=INNODB CHARSET=utf8; 插入性能单条插入单条插入的测试结果如下表所示:MariaDB 单条数据插入的性能比 MySQL 强 1 倍左右。批量插入批量插入的测试结果如下表所示:上面的测试结果,MariaDB 并没有绝对优势,甚至有时还比 MySQL 慢,但平均水平还是高于 MySQL。查询性能经过了多次插入测试,我两个数据库里插入了很多数据,此时用下面的 sql 查询表中的数据量:SELECT COUNT(0) FROM LOG 结果两个表都是 6785000 条,MariaDB 用时 3.065 秒,MySQL 用时 6.404 秒。此时我机器的内存用了 6 个 G,MariaDB 用了 474284 K,MySQL 只用了 66848 K。看来 MariaDB 快是牺牲了空间换取的。无索引先查询一下 time 字段的最大值和最小值:SELECT MAX(TIME), MIN(TIME) FROM LOG MariaDB 用时 6.333 秒,MySQL 用时 8.159 秒。接下来测试过滤 time 字段在 0 点到 1 点之间的数据,并对 time 字段排序:SELECT * FROM LOG WHERE TIME > '2020-02-04 00:00:00' AND TIME < '2020-02-04 01:00:00' ORDER BY TIME MariaDB 用时 6.996 秒,MySQL 用时 10.193 秒。然后测试查询 level 字符是 info 的数据:SELECT * FROM LOG WHERE LEVEL = 'info' MariaDB 用时 0.006 秒,MySQL 用时 0.049 秒。最后测试查询 message 字段值为 debug 的数据:SELECT * FROM LOG WHERE MESSAGE = 'debug' MariaDB 用时 0.003 秒,MySQL 用时 0.004 秒。有索引分别对两个数据库的字段创建索引:ALTER TABLE `performance`.`log`       ADD  INDEX `time` (`time`),    ADD  INDEX `level` (`level`),    ADD FULLTEXT INDEX `message` (`message`); MariaDB 用时 2 分 47 秒,MySQL 用时 3 分 48 秒。再用上面的测试项目进行测试,结果如下表所示:有些结果添加了索引后还不如不加索引时理想,说明实际使用时并不是每个字段都需要添加索引的。总结在上面的测试中 MariaDB 的性能的确优于 MySQL,看来各大厂商放弃 MySQL 拥抱 MariaDB 还是非常有道理的
  • [交流吐槽] 从输入 SQL 到返回数据,到底发生了什么?
    SQL 执行流程其实一个 SQL 从输入到返回数据,其过程大致为:建立连接、分析 SQL、优化 SQL、执行 SQL。建立连接当我们发送 SQL 给 MySQL 之前,我们都会输入账号和密码,从而与 MySQL 建立连接。这部分的工作,其实就是 MySQL 的连接器处理的。连接器负责跟客户端建立连接、获取权限、维持和管理连接。当我们用管理员账号对账号权限做修改后,不影响已经存在的连接的权限,只有新建的连接才会使用新的权限设置。我们可以通过 show processlist 命令查看目前的连接情况分析 SQL在 MySQL 8.0 版本之前,MySQL 拿到一个查询请求后,会先到查询缓存中看看是否有查过。如果有,那么直接返回缓存的结果。但在 8.0 版本之后,查询缓存功能直接被删除了。主要是因为查询缓存弊大于利。因为只要对一个表进行更新,这个表上的查询缓存就会被清空。可能你刚刚把结果缓存起来了,一个更新操作一来,这些缓存就全部失效了。所以查询缓存适合那些更新不频繁的表,用来提高查询效率。当拿到 SQL 之后,MySQL 会对 SQL 进行词法分析和语法分析。词法分析会解析每个词的含义,而语法分析则是解析语法是否准确,分析器先会做词法分析,再做语法分析。你输入的是由多个字符串和空格组成的一条 SQL 语句,MySQL 需要识别出里面的字符串分别是什么,代表什么。例如:select 表示查询,t 表示 t 这个表,字符串 ID 识别成列 ID。做完词法分析之后,就会做语法分析。根据词法分析的结果,语法分析器会根据语法规则,判断输入的 SQL 语句是否满足 MySQL 语法。如果不满足语法,会有「You have an error in your SQL syntax」的错误提醒。优化 SQL经过分析器,MySQL 就知道你要做什么了。但在开始执行之前,还要先经过优化器的处理。优化器是在表里面有多个索引的时候,决定使用哪个索引。或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。有时候两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。优化器阶段完成后,这个语句的执行方案就确定下来了,然后进入执行器阶段。执行 SQLMySQL 通过分析器知道了你要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。开始执行的时候,要先判断一下你对这个表 T 有没有执行查询的权限,如果没有,就会返回没有权限的错误。如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。例如对于 select * from T where ID=10; 这条语句,ID 字段没有索引,那么执行器的执行流程是这样的:调用 InnoDB 引擎接口取这个表的第一行,判断 ID 值是不是 10,如果不是则跳过,如果是则将这行存在结果集中。调用引擎接口取「下一行」,重复相同的判断逻辑,直到取到这个表的最后一行。执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。至此,这个语句就执行完成了。对于有索引的表,执行的逻辑也差不多。第一次调用的是「取满足条件的第一行」这个接口,之后循环取「满足条件的下一行」这个接口,这些接口都是引擎中已经定义好的。你会在数据库的慢查询日志中看到一个 rows_examined 的字段,表示这个语句在执行器执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。MySQL 技术架构其实上面的过程,就是按着 MySQL 的技术架构来的,其技术架构如下图所示。大体来说,MySQL 技术架构可以分为 Server 层和存储引擎层两部分。Server 层负责建立连接、分析 SQL 等功能。 所有跨存储引擎的功能都在这一层实现,例如存储过程、触发器、视图等。存储引擎层负责数据的存储和提取。 其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的是 InnoDB 存储引擎,从 MySQL 5.5.5 开始成为了默认的存储引擎。InnoDB 存储引擎目前使用最广泛的是 InnoDB 存储引擎,其体系架构分为三大块,分别是:后台线程、内存池、文件,其体系架构如下图所示。在上图中,后台线程负责刷新内存池的数据,内存池负责缓存磁盘的数据,文件则是具体的数据存储。后台线程的主要工作是负责刷新内存池的数据,保证缓冲池中的内存缓存的是最近的数据。InnoDB 存储引擎是多线程的模型,因此其后台有多个不同的后台线程,负责处理不同的任务。目前有 4 种不同类型的处理线程,分别是:Master Tread、IO Thread、Purge Thread、Page Cleaner Thread。内存池是 InnoDB 所管理内存的统称,主要用于缓存磁盘数据,从而加快数据的读取。根据其用途不同,内存池还可以分为:缓冲池、重做日志缓冲、额外内存池三大块。文件则是最终存取数据库数据的地方,其存储了包括索引文件、数据文件等相关的数据文件。总结最后我们总结一下一条 SQL 语句从查询到返回数据的 5 个阶段,分别是:建立连接。客户端会首先与 MySQL 建立 TCP 连接,在连接器中会进行连接管理、权限验证等操作。分析 SQL。分析器进行词法、语法分析,词法分析知道要查询什么内容,语法分析判断语法是否有问题。优化 SQL。优化器根据 SQL 情况,判断使用哪种执行方式更好,例如使用哪个索引,哪种表连接方式。执行 SQL。根据优化器的优化结果,生成执行计划,执行器调用存储引擎的 API 来执行查询,最终将数据返回给客户端。
  • [交流吐槽] MySQL常用查询Databases和Tables
    一、Databases and schemas列出了 MySQL 实例上的用户数据库(模式):select schema_name as database_name from information_schema.schemata where schema_name not in('mysql','information_schema', 'performance_schema','sys') order by schema_name说明:database_name - 数据库(模式)名称。二、Tables1. 列出 MySQL 数据库中的表下面的查询列出了当前或提供的数据库中的表。要列出所有用户数据库中的表(1) 当前数据库select table_schema as database_name, table_name from information_schema.tables where table_type = 'BASE TABLE' and table_schema = database() order by database_name, table_name;说明:table_schema - 数据库(模式)名称table_name - 表名(2) 指定数据库select table_schema as database_name, table_name from information_schema.tables where table_type = 'BASE TABLE' and table_schema = 'database_name' -- enter your database name here order by database_name, table_name;说明:table_schema - 数据库(模式)名称table_name - 表名2. 列出 MySQL 中所有数据库的表下面的查询列出了所有用户数据库中的所有表:select table_schema as database_name, table_name from information_schema.tables where table_type = 'BASE TABLE' and table_schema not in ('information_schema','mysql', 'performance_schema','sys') order by database_name, table_name;说明:table_schema - 数据库(模式)名称table_name - 表名3. 列出 MySQL 数据库中的 MyISAM 表select table_schema as database_name, table_name from information_schema.tables tab where engine = 'MyISAM' and table_type = 'BASE TABLE' and table_schema not in ('information_schema', 'sys', 'performance_schema','mysql') -- and table_schema = 'your database name' order by table_schema, table_name;说明:database_name - 数据库(模式)名称table_name - 表名4. 列出 MySQL 数据库中的 InnoDB 表select table_schema as database_name, table_name from information_schema.tables tab where engine = 'InnoDB' and table_type = 'BASE TABLE' and table_schema not in ('information_schema', 'sys', 'performance_schema','mysql') -- and table_schema = 'your database name' order by table_schema, table_name;说明:database_name - 数据库(模式)名称table_name - 表名5. 识别 MySQL 数据库中的表存储引擎(模式)select table_schema as database_name, table_name, engine from information_schema.tables where table_type = 'BASE TABLE' and table_schema not in ('information_schema','mysql', 'performance_schema','sys') -- and table_schema = 'your database name' order by table_schema, table_name;说明:(1)table_schema - 数据库(模式)名称(2)table_name - 表名(3)engine- 表存储引擎。可能的值:CSVInnoDB记忆MyISAM档案黑洞MRG_MyISAM联合的6. 在 MySQL 数据库中查找最近创建的表select table_schema as database_name, table_name, create_time from information_schema.tables where create_time > adddate(current_date,INTERVAL -60 DAY) and table_schema not in('information_schema', 'mysql', 'performance_schema','sys') and table_type ='BASE TABLE' -- and table_schema = 'your database name' order by create_time desc, table_schema;MySQL 数据库中最近 60 天内创建的所有表,按表的创建日期(降序)和数据库名称排序说明:database_name - 表所有者,模式名称table_name - 表名create_time - 表的创建日期7. 在 MySQL 数据库中查找最近修改的表select table_schema as database_name, table_name, update_time from information_schema.tables tab where update_time > (current_timestamp() - interval 30 day) and table_type = 'BASE TABLE' and table_schema not in ('information_schema', 'sys', 'performance_schema','mysql') -- and table_schema = 'your database name' order by update_time desc;所有数据库(模式)中最近 30 天内最后修改的所有表,按更新时间降序排列说明:database_name - 数据库(模式)名称table_name - 表名update_time - 表的最后更新时间(UPDATE、INSERT 或 DELETE 操作或 MVCC 的 COMMIT)
  • [交流吐槽] 关于MySQL数据库性能优化方法,看这一篇文章就够了
    数据库大量应用程序开发项目中,大多数情况下,数据库的操作性能成为整个应用的性能瓶颈。数据库的性能是程序员需要去关注的事情,当设计数据库表结构以及操作数据库(尤其是查询数据时),都需要注意数据操作的性能。本文我们以MySQL数据库为例进行讨论。一、数据库优化目标1. 减少 IO 次数IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当然,也是收效最明显的优化手段。2. 降低 CPU 计算除了 IO 瓶颈之外,SQL优化中需要考虑的就是 CPU 运算量的优化了。order by,group by,distinct … 都是消耗 CPU 的大户(这些操作基本上都是 CPU 处理内存中的数据比较运算)。当我们的 IO 优化做到一定阶段之后,降低 CPU计算也就成为了我们 SQL 优化的重要目标。二、数据库优化方法1. SQL语句优化明确了优化目标之后,我们需要确定达到我们目标的方法。对于SQL语句来说,达到上述2个优化目标的方法其实只有一个,那就是改变SQL的执行计划,让他尽量“少走弯路”,尽量通过各种“捷径”来找到我们需要的数据,以达到“减少IO次数”和“降低CPU计算”的目标。(1) 尽量少 join。MySQL 的优势在于简单,但这在某些方面其实也是其劣势。MySQL优化器效率高,但是由于其统计信息的量有限,优化器工作过程出现偏差的可能性也就更多。对于复杂的多表 Join,一方面由于其优化器受限,再者在Join这方面所下的功夫还不够,所以性能表现离Oracle等关系型数据库前辈还是有一定距离。但如果是简单的单表查询,这一差距就会极小甚至在有些场景下要优于这些数据库前辈。(2) 尽量少排序(3) 排序操作会消耗较多的 CPU 资源,所以减少排序可以在缓存命中率高等 IO 能力足够的场景下会较大影响 SQL的响应时间。(4) 尽量避免 select *,并尽量用join代替子查询(5) 尽量少使用“or”关键字当 where 子句中存在多个条件以“或”并存的时候,MySQL 的优化器并没有很好的解决其执行计划优化问题,再加上 MySQL 特有的 SQL 与 Storage 分层架构方式,造成了其性能比较低下,很多时候使用 union all 或者是union(必要的时候)的方式来代替“or”会得到更好的效果。(6) 尽量用 union all 代替 unionunion 和 union all 的差异主要是前者需要将两个(或者多个)结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。所以当我们可以确认不可能出现重复结果集或者不在乎重复结果集的时候,尽量使用 union all 而不是 union。(7) 避免类型转换(8) 能用DISTINCT的就不用GROUP BY(9) 尽量不要用SELECT INTO语句 ?(10) 从全局出发优化,而不是片面调整SQL 优化不能是单独针对某一个进行,而应充分考虑系统中所有的 SQL,尤其是在通过调整索引优化 SQL的执行计划的时候,千万不能顾此失彼,因小失大。2. 表结构优化MySQL数据库是基于行(Row)存储的数据库,而数据库操作 IO 的时候是以 page(block)的方式,也就是说,如果我们每条记录所占用的空间量减小,就会使每个page中可存放的数据行数增大,那么每次 IO 可访问的行数也就增多了。反过来说,处理相同行数的数据,需要访问的 page 就会减少,也就是 IO 操作次数降低,直接提升性能。(1) 数据类型选择原则是:数据行的长度不要超过8020字节,如果超过这个长度的话在物理页中这条数据会占用两行从而造成存储碎片,降低查询效率;字段的长度在最大限度的满足可能的需要的前提下,应该尽可能的设得短一些,这样可以提高查询的效率,而且在建立索引的时候也可以减少资源的消耗。数字类型:非万不得已不要使用DOUBLE,不仅仅只是存储长度的问题,同时还会存在精确性的问题。同样,固定精度的小数,也不建议使用DECIMAL,建议乘以固定倍数转换成整数存储,可以大大节省存储空间,且不会带来任何附加维护成本。字符类型:定长字段,建议使用 CHAR 类型(char查询快,但是耗存储空间,可用于用户名、密码等长度变化不大的字段),不定长字段尽量使用VARCHAR(varchar查询相对慢一些但是节省存储空间,可用于评论等长度变化大的字段),且仅仅设定适当的最大长度,而不是非常随意的给一个很大的最大长度限定,因为不同的长度范围,MySQL也会有不一样的存储处理。时间类型:尽量使用TIMESTAMP类型,因为其存储空间只需要DATETIME 类型的一半。对于只需要精确到某一天的数据类型,建议使用DATE类型,因为他的存储空间只需要3个字节,比TIMESTAMP还少。不建议通过INT类型类存储一个unix timestamp 的值,因为这太不直观,会给维护带来不必要的麻烦,同时还不会带来任何好处。ENUM &SET:对于状态字段,可以尝试使用 ENUM 来存放,因为可以极大的降低存储空间,而且即使需要增加新的类型,只要增加于末尾,修改结构也不需要重建表数据。(2) 字符编码字符集直接决定了数据在MySQL中的存储编码方式,由于同样的内容使用不同字符集表示所占用的空间大小会有较大的差异,所以通过使用合适的字符集,可以帮助我们尽可能减少数据量,进而减少IO操作次数。(3) 尽量使用 NOT NULLNULL 类型比较特殊,SQL 难优化。虽然 MySQL NULL类型和 Oracle 的NULL有差异,会进入索引中,但如果是一个组合索引,那么这个NULL 类型的字段会极大影响整个索引的效率。虽然 NULL空间上可能确实有一定节省,倒是带来了很多其他的优化问题,不但没有将IO量省下来,反而加大了SQL的IO量。所以尽量确保 DEFAULT 值不是 NULL,也是一个很好的表结构设计优化习惯。3. 数据库架构优化分布式和集群化:负载均衡。负载均衡集群是由一组相互独立的计算机系统构成,通过常规网络或专用网络进行连接,由路由器衔接在一起,各节点相互协作、共同负载、均衡压力,对客户端来说,整个群集可以视为一台具有超高性能的独立服务器。MySQL一般部署的是高可用性负载均衡集群,具备读写分离,一般只对读进行负载均衡。读写分离。读写分离简单的说是把对数据库读和写的操作分开对应不同的数据库服务器,这样能有效地减轻数据库压力,也能减轻io压力。主数据库提供写操作,从数据库提供读操作,其实在很多系统中,主要是读的操作。当主数据库进行写操作时,数据要同步到从的数据库,这样才能有效保证数据库完整性。数据切分。通过某种特定的条件,将存放在同一个数据库中的数据分散存放到多个数据库上,实现分布存储,通过路由规则路由访问特定的数据库,这样一来每次访问面对的就不是单台服务器了,而是N台服务器,这样就可以降低单台机器的负载压力。4. 其他优化(1) 适当使用视图加速查询。把表的一个子集进行排序并创建视图,有时能加速查询(特别是要被多次执行的查询)。它有助于避免多重排序操作,而且在其他方面还能简化优化器的工作。视图中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询工作量可以得到大幅减少。(2) 算法优化。尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。(3)封装存储过程。经编译和优化后存储在数据库服务器中,运行效率高,可以降低客户机和服务器之间的通信量,有利于集中控制,易于维护。
  • [问题求助] mysql数据库库中的数据被人删除后能否恢复
    问题描述:mysql数据库中有两个库被黑客删除了,它向我勒索,而我目前环境只有4.21日的快照,但我想恢复数据到5.24,有啥办法可以恢复吗?
总条数:1406 到第
上滑加载中