精华内容
下载资源
问答
  • MySQL数据库面试题(2020最新版)

    万次阅读 多人点赞 2020-03-10 17:20:40
    文章目录数据库基础知识为什么要使用数据库什么是SQL?什么是MySQL?数据库三大范式是什么mysql有关权限的表都有哪几个MySQL的binlog有有几种录入格式?分别有什么区别?数据类型mysql有哪些数据类型引擎MySQL存储...

    大家好,我是CSDN的博主ThinkWon,“2020博客之星年度总评选"开始啦,希望大家帮我投票,每天都可以投多票哦,点击下方链接,然后点击"最大”,再点击"投TA一票"就可以啦!
    投票链接:https://bss.csdn.net/m/topic/blog_star2020/detail?username=thinkwon
    在技术的世界里,ThinkWon将一路与你相伴!创作出更多更高质量的文章!2020为努力奋斗的你点赞👍,️新的一年,祝各位大牛牛气冲天,牛年大吉!😊😊

    文章目录

    Java面试总结汇总,整理了包括Java基础知识,集合容器,并发编程,JVM,常用开源框架Spring,MyBatis,数据库,中间件等,包含了作为一个Java工程师在面试中需要用到或者可能用到的绝大部分知识。欢迎大家阅读,本人见识有限,写的博客难免有错误或者疏忽的地方,还望各位大佬指点,在此表示感激不尽。文章持续更新中…

    序号 内容 链接地址
    1 Java基础知识面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104390612
    2 Java集合容器面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104588551
    3 Java异常面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104390689
    4 并发编程面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104863992
    5 JVM面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104390752
    6 Spring面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104397516
    7 Spring MVC面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104397427
    8 Spring Boot面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104397299
    9 Spring Cloud面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104397367
    10 MyBatis面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/101292950
    11 Redis面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/103522351
    12 MySQL数据库面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104778621
    13 消息中间件MQ与RabbitMQ面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104588612
    14 Dubbo面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104390006
    15 Linux面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104588679
    16 Tomcat面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104397665
    17 ZooKeeper面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104397719
    18 Netty面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/104391081
    19 架构设计&分布式&数据结构与算法面试题(2020最新版) https://thinkwon.blog.csdn.net/article/details/105870730

    数据库基础知识

    为什么要使用数据库

    数据保存在内存

    优点: 存取速度快

    缺点: 数据不能永久保存

    数据保存在文件

    优点: 数据永久保存

    缺点:1)速度比内存操作慢,频繁的IO操作。2)查询数据不方便

    数据保存在数据库

    1)数据永久保存

    2)使用SQL语句,查询方便效率高。

    3)管理数据方便

    什么是SQL?

    结构化查询语言(Structured Query Language)简称SQL,是一种数据库查询语言。

    作用:用于存取数据、查询、更新和管理关系数据库系统。

    什么是MySQL?

    MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。在Java企业级开发中非常常用,因为 MySQL 是开源免费的,并且方便扩展。

    数据库三大范式是什么

    第一范式:每个列都不可以再拆分。

    第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。

    第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。

    在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上我们经常会为了性能而妥协数据库的设计。

    mysql有关权限的表都有哪几个

    MySQL服务器通过权限表来控制用户对数据库的访问,权限表存放在mysql数据库里,由mysql_install_db脚本初始化。这些权限表分别user,db,table_priv,columns_priv和host。下面分别介绍一下这些表的结构和内容:

    • user权限表:记录允许连接到服务器的用户帐号信息,里面的权限是全局级的。
    • db权限表:记录各个帐号在各个数据库上的操作权限。
    • table_priv权限表:记录数据表级的操作权限。
    • columns_priv权限表:记录数据列级的操作权限。
    • host权限表:配合db权限表对给定主机上数据库级操作权限作更细致的控制。这个权限表不受GRANT和REVOKE语句的影响。

    MySQL的binlog有有几种录入格式?分别有什么区别?

    有三种格式,statement,row和mixed。

    • statement模式下,每一条会修改数据的sql都会记录在binlog中。不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制。
    • row级别下,不记录sql语句上下文相关信息,仅保存哪条记录被修改。记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如alter table),因此这种模式的文件保存的信息太多,日志量太大。
    • mixed,一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row。

    此外,新版的MySQL中对row级别也做了一些优化,当表结构发生变化的时候,会记录语句而不是逐行记录。

    数据类型

    mysql有哪些数据类型

    分类 类型名称 说明
    整数类型 tinyInt 很小的整数(8位二进制)
    smallint 小的整数(16位二进制)
    mediumint 中等大小的整数(24位二进制)
    int(integer) 普通大小的整数(32位二进制)
    小数类型 float 单精度浮点数
    double 双精度浮点数
    decimal(m,d) 压缩严格的定点数
    日期类型 year YYYY 1901~2155
    time HH:MM:SS -838:59:59~838:59:59
    date YYYY-MM-DD 1000-01-01~9999-12-3
    datetime YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00~ 9999-12-31 23:59:59
    timestamp YYYY-MM-DD HH:MM:SS 19700101 00:00:01 UTC~2038-01-19 03:14:07UTC
    文本、二进制类型 CHAR(M) M为0~255之间的整数
    VARCHAR(M) M为0~65535之间的整数
    TINYBLOB 允许长度0~255字节
    BLOB 允许长度0~65535字节
    MEDIUMBLOB 允许长度0~167772150字节
    LONGBLOB 允许长度0~4294967295字节
    TINYTEXT 允许长度0~255字节
    TEXT 允许长度0~65535字节
    MEDIUMTEXT 允许长度0~167772150字节
    LONGTEXT 允许长度0~4294967295字节
    VARBINARY(M) 允许长度0~M个字节的变长字节字符串
    BINARY(M) 允许长度0~M个字节的定长字节字符串
    • 1、整数类型,包括TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分别表示1字节、2字节、3字节、4字节、8字节整数。任何整数类型都可以加上UNSIGNED属性,表示数据是无符号的,即非负整数。
      长度:整数类型可以被指定长度,例如:INT(11)表示长度为11的INT类型。长度在大多数场景是没有意义的,它不会限制值的合法范围,只会影响显示字符的个数,而且需要和UNSIGNED ZEROFILL属性配合使用才有意义。
      例子,假定类型设定为INT(5),属性为UNSIGNED ZEROFILL,如果用户插入的数据为12的话,那么数据库实际存储数据为00012。

    • 2、实数类型,包括FLOAT、DOUBLE、DECIMAL。
      DECIMAL可以用于存储比BIGINT还大的整型,能存储精确的小数。
      而FLOAT和DOUBLE是有取值范围的,并支持使用标准的浮点进行近似计算。
      计算时FLOAT和DOUBLE相比DECIMAL效率更高一些,DECIMAL你可以理解成是用字符串进行处理。

    • 3、字符串类型,包括VARCHAR、CHAR、TEXT、BLOB
      VARCHAR用于存储可变长字符串,它比定长类型更节省空间。
      VARCHAR使用额外1或2个字节存储字符串长度。列长度小于255字节时,使用1字节表示,否则使用2字节表示。
      VARCHAR存储的内容超出设置的长度时,内容会被截断。
      CHAR是定长的,根据定义的字符串长度分配足够的空间。
      CHAR会根据需要使用空格进行填充方便比较。
      CHAR适合存储很短的字符串,或者所有值都接近同一个长度。
      CHAR存储的内容超出设置的长度时,内容同样会被截断。

      使用策略:
      对于经常变更的数据来说,CHAR比VARCHAR更好,因为CHAR不容易产生碎片。
      对于非常短的列,CHAR比VARCHAR在存储空间上更有效率。
      使用时要注意只分配需要的空间,更长的列排序时会消耗更多内存。
      尽量避免使用TEXT/BLOB类型,查询时会使用临时表,导致严重的性能开销。

    • 4、枚举类型(ENUM),把不重复的数据存储为一个预定义的集合。
      有时可以使用ENUM代替常用的字符串类型。
      ENUM存储非常紧凑,会把列表值压缩到一个或两个字节。
      ENUM在内部存储时,其实存的是整数。
      尽量避免使用数字作为ENUM枚举的常量,因为容易混乱。
      排序是按照内部存储的整数

    • 5、日期和时间类型,尽量使用timestamp,空间效率高于datetime,
      用整数保存时间戳通常不方便处理。
      如果需要存储微妙,可以使用bigint存储。
      看到这里,这道真题是不是就比较容易回答了。

    引擎

    MySQL存储引擎MyISAM与InnoDB区别

    存储引擎Storage engine:MySQL中的数据、索引以及其他对象是如何存储的,是一套文件系统的实现。

    常用的存储引擎有以下:

    • Innodb引擎:Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。
    • MyIASM引擎(原本Mysql的默认引擎):不提供事务的支持,也不支持行级锁和外键。
    • MEMORY引擎:所有的数据都在内存中,数据的处理速度快,但是安全性不高。

    MyISAM与InnoDB区别

    MyISAM Innodb
    存储结构 每张表被存放在三个文件:frm-表格定义、MYD(MYData)-数据文件、MYI(MYIndex)-索引文件 所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB
    存储空间 MyISAM可被压缩,存储空间较小 InnoDB的表需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引
    可移植性、备份及恢复 由于MyISAM的数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进行操作 免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十G的时候就相对痛苦了
    文件格式 数据和索引是分别存储的,数据.MYD,索引.MYI 数据和索引是集中存储的,.ibd
    记录存储顺序 按记录插入顺序保存 按主键大小有序插入
    外键 不支持 支持
    事务 不支持 支持
    锁支持(锁是避免资源争用的一个机制,MySQL锁对用户几乎是透明的) 表级锁定 行级锁定、表级锁定,锁定力度小并发能力高
    SELECT MyISAM更优
    INSERT、UPDATE、DELETE InnoDB更优
    select count(*) myisam更快,因为myisam内部维护了一个计数器,可以直接调取。
    索引的实现方式 B+树索引,myisam 是堆表 B+树索引,Innodb 是索引组织表
    哈希索引 不支持 支持
    全文索引 支持 不支持

    MyISAM索引与InnoDB索引的区别?

    • InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引。
    • InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效。
    • MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。
    • InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查询时做到覆盖索引会非常高效。

    InnoDB引擎的4大特性

    • 插入缓冲(insert buffer)

    • 二次写(double write)

    • 自适应哈希索引(ahi)

    • 预读(read ahead)

    存储引擎选择

    如果没有特别的需求,使用默认的Innodb即可。

    MyISAM:以读写插入为主的应用程序,比如博客系统、新闻门户网站。

    Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,支持事务和外键。比如OA自动化办公系统。

    索引

    什么是索引?

    索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。

    索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。

    更通俗的说,索引就相当于目录。为了方便查找书中的内容,通过对内容建立索引形成目录。索引是一个文件,它是要占据物理空间的。

    索引有哪些优缺点?

    索引的优点

    • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
    • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

    索引的缺点

    • 时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
    • 空间方面:索引需要占物理空间。

    索引使用场景(重点)

    where

    img

    上图中,根据id查询记录,因为id字段仅建立了主键索引,因此此SQL执行可选的索引只有主键索引,如果有多个,最终会选一个较优的作为检索的依据。

    -- 增加一个没有建立索引的字段
    alter table innodb1 add sex char(1);
    -- 按sex检索时可选的索引为null
    EXPLAIN SELECT * from innodb1 where sex='男';
    

    img

    可以尝试在一个字段未建立索引时,根据该字段查询的效率,然后对该字段建立索引(alter table 表名 add index(字段名)),同样的SQL执行的效率,你会发现查询效率会有明显的提升(数据量越大越明显)。

    order by

    当我们使用order by将查询结果按照某个字段排序时,如果该字段没有建立索引,那么执行计划会将查询出的所有数据使用外部排序(将数据从硬盘分批读取到内存使用内部排序,最后合并排序结果),这个操作是很影响性能的,因为需要将查询涉及到的所有数据从磁盘中读到内存(如果单条数据过大或者数据量过多都会降低效率),更无论读到内存之后的排序了。

    但是如果我们对该字段建立索引alter table 表名 add index(字段名),那么由于索引本身是有序的,因此直接按照索引的顺序和映射关系逐条取出数据即可。而且如果分页的,那么只用取出索引表某个范围内的索引对应的数据,而不用像上述那取出所有数据进行排序再返回某个范围内的数据。(从磁盘取数据是最影响性能的)

    join

    join语句匹配关系(on)涉及的字段建立索引能够提高效率

    索引覆盖

    如果要查询的字段都建立过索引,那么引擎会直接在索引表中查询而不会访问原始数据(否则只要有一个字段没有建立索引就会做全表扫描),这叫索引覆盖。因此我们需要尽可能的在select只写必要的查询字段,以增加索引覆盖的几率。

    这里值得注意的是不要想着为每个字段建立索引,因为优先使用索引的优势就在于其体积小。

    索引有哪几种类型?

    主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。

    唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。

    • 可以通过 ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引

    • 可以通过 ALTER TABLE table_name ADD UNIQUE (column1,column2); 创建唯一组合索引

    普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。

    • 可以通过ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引

    • 可以通过ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);创建组合索引

    全文索引: 是目前搜索引擎使用的一种关键技术。

    • 可以通过ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引

    索引的数据结构(b树,hash)

    索引的数据结构和具体存储引擎的实现有关,在MySQL中使用较多的索引有Hash索引B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引实现为:B+树索引。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。

    1)B树索引

    mysql通过存储引擎取数据,基本上90%的人用的就是InnoDB了,按照实现方式分,InnoDB的索引类型目前只有两种:BTREE(B树)索引和HASH索引。B树索引是Mysql数据库中使用最频繁的索引类型,基本所有存储引擎都支持BTree索引。通常我们说的索引不出意外指的就是(B树)索引(实际是用B+树实现的,因为在查看表索引时,mysql一律打印BTREE,所以简称为B树索引)

    img

    查询方式:

    主键索引区:PI(关联保存的时数据的地址)按主键查询,

    普通索引区:si(关联的id的地址,然后再到达上面的地址)。所以按主键查询,速度最快

    B+tree性质:

    1.)n棵子tree的节点包含n个关键字,不用来保存数据而是保存数据的索引。

    2.)所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

    3.)所有的非终端结点可以看成是索引部分,结点中仅含其子树中的最大(或最小)关键字。

    4.)B+ 树中,数据对象的插入和删除仅在叶节点上进行。

    5.)B+树有2个头指针,一个是树的根节点,一个是最小关键码的叶节点。

    2)哈希索引

    简要说下,类似于数据结构中简单实现的HASH表(散列表)一样,当我们在mysql中用哈希索引时,主要就是通过Hash算法(常见的Hash算法有直接定址法、平方取中法、折叠法、除数取余法、随机数法),将数据库字段数据转换成定长的Hash值,与这条数据的行指针一并存入Hash表的对应位置;如果发生Hash碰撞(两个不同关键字的Hash值相同),则在对应Hash键下以链表形式存储。当然这只是简略模拟图。

    img

    索引的基本原理

    索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。

    索引的原理很简单,就是把无序的数据变成有序的查询

    1. 把创建了索引的列的内容进行排序

    2. 对排序结果生成倒排表

    3. 在倒排表内容上拼上数据地址链

    4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

    索引算法有哪些?

    索引算法有 BTree算法和Hash算法

    BTree算法

    BTree是最常用的mysql数据库索引算法,也是mysql默认的算法。因为它不仅可以被用在=,>,>=,<,<=和between这些比较操作符上,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量, 例如:

    -- 只要它的查询条件是一个不以通配符开头的常量
    select * from user where name like 'jack%'; 
    -- 如果一通配符开头,或者没有使用常量,则不会使用索引,例如: 
    select * from user where name like '%jack'; 
    

    Hash算法

    Hash Hash索引只能用于对等比较,例如=,<=>(相当于=)操作符。由于是一次定位数据,不像BTree索引需要从根节点到枝节点,最后才能访问到页节点这样多次IO访问,所以检索效率远高于BTree索引。

    索引设计的原则?

    1. 适合索引的列是出现在where子句中的列,或者连接子句中指定的列
    2. 基数较小的类,索引效果较差,没有必要在此列建立索引
    3. 使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样能够节省大量索引空间
    4. 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长。所以只保持需要的索引有利于查询即可。

    创建索引的原则(重中之重)

    索引虽好,但也不是无限制的使用,最好符合一下几个原则

    1) 最左前缀匹配原则,组合索引非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

    2)较频繁作为查询条件的字段才去创建索引

    3)更新频繁字段不适合创建索引

    4)若是不能有效区分数据的列不适合做索引列(如性别,男女未知,最多也就三种,区分度实在太低)

    5)尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

    6)定义有外键的数据列一定要建立索引。

    7)对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。

    8)对于定义为text、image和bit的数据类型的列不要建立索引。

    创建索引的三种方式,删除索引

    第一种方式:在执行CREATE TABLE时创建索引

    CREATE TABLE user_index2 (
    	id INT auto_increment PRIMARY KEY,
    	first_name VARCHAR (16),
    	last_name VARCHAR (16),
    	id_card VARCHAR (18),
    	information text,
    	KEY name (first_name, last_name),
    	FULLTEXT KEY (information),
    	UNIQUE KEY (id_card)
    );
    

    第二种方式:使用ALTER TABLE命令去增加索引

    ALTER TABLE table_name ADD INDEX index_name (column_list);
    

    ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。

    其中table_name是要增加索引的表名,column_list指出对哪些列进行索引,多列时各列之间用逗号分隔。

    索引名index_name可自己命名,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTER TABLE允许在单个语句中更改多个表,因此可以在同时创建多个索引。

    第三种方式:使用CREATE INDEX命令创建

    CREATE INDEX index_name ON table_name (column_list);
    

    CREATE INDEX可对表增加普通索引或UNIQUE索引。(但是,不能创建PRIMARY KEY索引)

    删除索引

    根据索引名删除普通索引、唯一索引、全文索引:alter table 表名 drop KEY 索引名

    alter table user_index drop KEY name;
    alter table user_index drop KEY id_card;
    alter table user_index drop KEY information;
    

    删除主键索引:alter table 表名 drop primary key(因为主键只有一个)。这里值得注意的是,如果主键自增长,那么不能直接执行此操作(自增长依赖于主键索引):

    img

    需要取消自增长再行删除:

    alter table user_index
    -- 重新定义字段
    MODIFY id int,
    drop PRIMARY KEY
    

    但通常不会删除主键,因为设计主键一定与业务逻辑无关。

    创建索引时需要注意什么?

    • 非空字段:应该指定列为NOT NULL,除非你想存储NULL。在mysql中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值;
    • 取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过count()函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高;
    • 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高。

    使用索引查询一定能提高查询的性能吗?为什么

    通常,通过索引查询数据比全表扫描要快。但是我们也必须注意到它的代价。

    • 索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时,索引本身也会被修改。 这意味着每条记录的INSERT,DELETE,UPDATE将为此多付出4,5 次的磁盘I/O。 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询性能,索引范围查询(INDEX RANGE SCAN)适用于两种情况:
    • 基于一个范围的检索,一般查询返回结果集小于表中记录数的30%
    • 基于非唯一性索引的检索

    百万级别或以上的数据如何删除

    关于索引:由于索引需要额外的维护成本,因为索引文件是单独存在的文件,所以当我们对数据的增加,修改,删除,都会产生额外的对索引文件的操作,这些操作需要消耗额外的IO,会降低增/改/删的执行效率。所以,在我们删除数据库百万级别数据的时候,查询MySQL官方手册得知删除数据的速度和创建的索引数量是成正比的。

    1. 所以我们想要删除百万数据的时候可以先删除索引(此时大概耗时三分多钟)
    2. 然后删除其中无用数据(此过程需要不到两分钟)
    3. 删除完成后重新创建索引(此时数据较少了)创建索引也非常快,约十分钟左右。
    4. 与之前的直接删除绝对是要快速很多,更别说万一删除中断,一切删除会回滚。那更是坑了。

    前缀索引

    语法:index(field(10)),使用字段值的前10个字符建立索引,默认是使用字段的全部内容建立索引。

    前提:前缀的标识度高。比如密码就适合建立前缀索引,因为密码几乎各不相同。

    实操的难度:在于前缀截取的长度。

    我们可以利用select count(*)/count(distinct left(password,prefixLen));,通过从调整prefixLen的值(从1自增)查看不同前缀长度的一个平均匹配度,接近1时就可以了(表示一个密码的前prefixLen个字符几乎能确定唯一一条记录)

    什么是最左前缀原则?什么是最左匹配原则

    • 顾名思义,就是最左优先,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。
    • 最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
    • =和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式

    B树和B+树的区别

    • 在B树中,你可以将键和值存放在内部节点和叶子节点;但在B+树中,内部节点都是键,没有值,叶子节点同时存放键和值。

    • B+树的叶子节点有一条链相连,而B树的叶子节点各自独立。

      img

    使用B树的好处

    B树可以在内部节点同时存储键和值,因此,把频繁访问的数据放在靠近根节点的地方将会大大提高热点数据的查询效率。这种特性使得B树在特定数据重复多次查询的场景中更加高效。

    使用B+树的好处

    由于B+树的内部节点只存放键,不存放值,因此,一次读取,可以在内存页中获取更多的键,有利于更快地缩小查找范围。 B+树的叶节点由一条链相连,因此,当需要进行一次全数据遍历的时候,B+树只需要使用O(logN)时间找到最小的一个节点,然后通过链进行O(N)的顺序遍历即可。而B树则需要对树的每一层进行遍历,这会需要更多的内存置换次数,因此也就需要花费更多的时间

    Hash索引和B+树所有有什么区别或者说优劣呢?

    首先要知道Hash索引和B+树索引的底层实现原理:

    hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据。B+树底层实现是多路平衡查找树。对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据。

    那么可以看出他们有以下的不同:

    • hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询。

    因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询。而B+树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围。

    • hash索引不支持使用索引进行排序,原理同上。
    • hash索引不支持模糊查询以及多列索引的最左前缀匹配。原理也是因为hash函数的不可预测。AAAA和AAAAB的索引没有相关性。
    • hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询。
    • hash索引虽然在等值查询上较快,但是不稳定。性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差。而B+树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低。

    因此,在大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度。而不需要使用hash索引。

    数据库为什么使用B+树而不是B树

    • B树只适合随机检索,而B+树同时支持随机检索和顺序检索;
    • B+树空间利用率更高,可减少I/O次数,磁盘读写代价更低。一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O消耗。B+树的内部结点并没有指向关键字具体信息的指针,只是作为索引使用,其内部结点比B树小,盘块能容纳的结点中关键字数量更多,一次性读入内存中可以查找的关键字也就越多,相对的,IO读写次数也就降低了。而IO读写次数是影响索引检索效率的最大因素;
    • B+树的查询效率更加稳定。B树搜索有可能会在非叶子结点结束,越靠近根节点的记录查找时间越短,只要找到关键字即可确定记录的存在,其性能等价于在关键字全集内做一次二分查找。而在B+树中,顺序检索比较明显,随机检索时,任何关键字的查找都必须走一条从根节点到叶节点的路,所有关键字的查找路径长度相同,导致每一个关键字的查询效率相当。
    • B-树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。B+树的叶子节点使用指针顺序连接在一起,只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作。
    • 增删文件(节点)时,效率更高。因为B+树的叶子节点包含所有关键字,并以有序的链表结构存储,这样可很好提高增删效率。

    B+树在满足聚簇索引和覆盖索引的时候不需要回表查询数据,

    在B+树的索引中,叶子节点可能存储了当前的key值,也可能存储了当前的key值以及整行的数据,这就是聚簇索引和非聚簇索引。 在InnoDB中,只有主键索引是聚簇索引,如果没有主键,则挑选一个唯一键建立聚簇索引。如果没有唯一键,则隐式的生成一个键来建立聚簇索引。

    当查询使用聚簇索引时,在对应的叶子节点,可以获取到整行数据,因此不用再次进行回表查询。

    什么是聚簇索引?何时使用聚簇索引与非聚簇索引

    • 聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据
    • 非聚簇索引:将数据存储于索引分开结构,索引结构的叶子节点指向了数据的对应行,myisam通过key_buffer把索引先缓存到内存中,当需要访问数据时(通过索引访问数据),在内存中直接搜索索引,然后通过索引找到磁盘相应数据,这也就是为什么索引不在key buffer命中时,速度慢的原因

    澄清一个概念:innodb中,在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引,辅助索引叶子节点存储的不再是行的物理位置,而是主键值

    何时使用聚簇索引与非聚簇索引

    img

    非聚簇索引一定会回表查询吗?

    不一定,这涉及到查询语句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再进行回表查询。

    举个简单的例子,假设我们在员工表的年龄上建立了索引,那么当进行select age from employee where age < 20的查询时,在索引的叶子节点上,已经包含了age信息,不会再次进行回表查询。

    联合索引是什么?为什么需要注意联合索引中的顺序?

    MySQL可以使用多个字段同时建立一个索引,叫做联合索引。在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引。

    具体原因为:

    MySQL使用索引时需要索引有序,假设现在建立了"name,age,school"的联合索引,那么索引的排序为: 先按照name排序,如果name相同,则按照age排序,如果age的值也相等,则按照school进行排序。

    当进行查询时,此时索引仅仅按照name严格有序,因此必须首先使用name字段进行等值查询,之后对于匹配到的列而言,其按照age字段严格有序,此时可以使用age字段用做索引查找,以此类推。因此在建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询需求频繁或者字段选择性高的列放在前面。此外可以根据特例的查询或者表结构进行单独的调整。

    事务

    什么是数据库事务?

    事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。

    事务最经典也经常被拿出来说例子就是转账了。

    假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。

    事物的四大特性(ACID)介绍一下?

    关系性数据库需要遵循ACID规则,具体内容如下:

    事务的特性

    1. 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
    2. 一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
    3. 隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
    4. 持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

    什么是脏读?幻读?不可重复读?

    • 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
    • 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
    • 幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

    什么是事务的隔离级别?MySQL的默认隔离级别是什么?

    为了达到事务的四大特性,数据库定义了4种不同的事务隔离级别,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。

    隔离级别 脏读 不可重复读 幻影读
    READ-UNCOMMITTED
    READ-COMMITTED ×
    REPEATABLE-READ × ×
    SERIALIZABLE × × ×

    SQL 标准定义了四个隔离级别:

    • READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
    • READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
    • REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
    • SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读

    这里需要注意的是:Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别

    事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。

    因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容):,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。

    InnoDB 存储引擎在 分布式事务 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。

    对MySQL的锁了解吗

    当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。

    就像酒店的房间,如果大家随意进出,就会出现多人抢夺同一个房间的情况,而在房间上装上锁,申请到钥匙的人才可以入住并且将房间锁起来,其他人只有等他使用完毕才可以再次使用。

    隔离级别与锁的关系

    在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突

    在Read Committed级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁;

    在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁。

    SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。

    按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法

    在关系型数据库中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。

    MyISAM和InnoDB存储引擎使用的锁:

    • MyISAM采用表级锁(table-level locking)。
    • InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁

    行级锁,表级锁和页级锁对比

    行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。

    特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

    表级锁 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。

    特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

    页级锁 页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。

    特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

    从锁的类别上分MySQL都有哪些锁呢?像上面那样子进行锁定岂不是有点阻碍并发效率了

    从锁的类别上来讲,有共享锁和排他锁。

    共享锁: 又叫做读锁。 当用户要进行数据的读取时,对数据加上共享锁。共享锁可以同时加上多个。

    排他锁: 又叫做写锁。 当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁,共享锁都相斥。

    用上面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是可以接受的。 一种是真正的入住一晚,在这期间,无论是想入住的还是想看房的都不可以。

    锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁。

    他们的加锁开销从大到小,并发能力也是从大到小。

    MySQL中InnoDB引擎的行锁是怎么实现的?

    答:InnoDB是基于索引来完成行锁

    例: select * from tab_with_index where id = 1 for update;

    for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么InnoDB将完成表锁,并发将无从谈起

    InnoDB存储引擎的锁的算法有三种

    • Record lock:单个行记录上的锁
    • Gap lock:间隙锁,锁定一个范围,不包括记录本身
    • Next-key lock:record+gap 锁定一个范围,包含记录本身

    相关知识点:

    1. innodb对于行的查询使用next-key lock
    2. Next-locking keying为了解决Phantom Problem幻读问题
    3. 当查询的索引含有唯一属性时,将next-key lock降级为record key
    4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
    5. 有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1

    什么是死锁?怎么解决?

    死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。

    常见的解决死锁的方法

    1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

    2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;

    3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

    如果业务处理不好可以用分布式事务锁或者使用乐观锁

    数据库的乐观锁和悲观锁是什么?怎么实现的?

    数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

    悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制

    乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐一般会使用版本号机制或CAS算法实现。

    两种锁的使用场景

    从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。

    但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。

    视图

    为什么要使用视图?什么是视图?

    为了提高复杂SQL语句的复用性和表操作的安全性,MySQL数据库管理系统提供了视图特性。所谓视图,本质上是一种虚拟表,在物理上是不存在的,其内容与真实的表相似,包含一系列带有名称的列和行数据。但是,视图并不在数据库中以储存的数据值形式存在。行和列数据来自定义视图的查询所引用基本表,并且在具体引用视图时动态生成。

    视图使开发者只关心感兴趣的某些特定数据和所负责的特定任务,只能看到视图中所定义的数据,而不是视图所引用表中的数据,从而提高了数据库中数据的安全性。

    视图有哪些特点?

    视图的特点如下:

    • 视图的列可以来自不同的表,是表的抽象和在逻辑意义上建立的新关系。

    • 视图是由基本表(实表)产生的表(虚表)。

    • 视图的建立和删除不影响基本表。

    • 对视图内容的更新(添加,删除和修改)直接影响基本表。

    • 当视图来自多个基本表时,不允许添加和删除数据。

    视图的操作包括创建视图,查看视图,删除视图和修改视图。

    视图的使用场景有哪些?

    视图根本用途:简化sql查询,提高开发效率。如果说还有另外一个用途那就是兼容老的表结构。

    下面是视图的常见使用场景:

    • 重用SQL语句;

    • 简化复杂的SQL操作。在编写查询后,可以方便的重用它而不必知道它的基本查询细节;

    • 使用表的组成部分而不是整个表;

    • 保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限;

    • 更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。

    视图的优点

    1. 查询简单化。视图能简化用户的操作
    2. 数据安全性。视图使用户能以多种角度看待同一数据,能够对机密数据提供安全保护
    3. 逻辑数据独立性。视图对重构数据库提供了一定程度的逻辑独立性

    视图的缺点

    1. 性能。数据库必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,数据库也把它变成一个复杂的结合体,需要花费一定的时间。

    2. 修改限制。当用户试图修改视图的某些行时,数据库必须把它转化为对基本表的某些行的修改。事实上,当从视图中插入或者删除时,情况也是这样。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的

      这些视图有如下特征:1.有UNIQUE等集合操作符的视图。2.有GROUP BY子句的视图。3.有诸如AVG\SUM\MAX等聚合函数的视图。 4.使用DISTINCT关键字的视图。5.连接表的视图(其中有些例外)

    什么是游标?

    游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果,每个游标区都有一个名字。用户可以通过游标逐一获取记录并赋给主变量,交由主语言进一步处理。

    存储过程与函数

    什么是存储过程?有哪些优缺点?

    存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需要创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。

    优点

    1)存储过程是预编译过的,执行效率高。

    2)存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。

    3)安全性高,执行存储过程需要有一定权限的用户。

    4)存储过程可以重复使用,减少数据库开发人员的工作量。

    缺点

    1)调试麻烦,但是用 PL/SQL Developer 调试很方便!弥补这个缺点。

    2)移植问题,数据库端代码当然是与数据库相关的。但是如果是做工程型项目,基本不存在移植问题。

    3)重新编译问题,因为后端代码是运行前编译的,如果带有引用关系的对象发生改变时,受影响的存储过程、包将需要重新编译(不过也可以设置成运行时刻自动编译)。

    4)如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难、而且代价是空前的,维护起来更麻烦。

    触发器

    什么是触发器?触发器的使用场景有哪些?

    触发器是用户定义在关系表上的一类由事件驱动的特殊的存储过程。触发器是指一段代码,当触发某个事件时,自动执行这些代码。

    使用场景

    • 可以通过数据库中的相关表实现级联更改。
    • 实时监控某张表中的某个字段的更改而需要做出相应的处理。
    • 例如可以生成某些业务的编号。
    • 注意不要滥用,否则会造成数据库及应用程序的维护困难。
    • 大家需要牢记以上基础知识点,重点是理解数据类型CHAR和VARCHAR的差异,表存储引擎InnoDB和MyISAM的区别。

    MySQL中都有哪些触发器?

    在MySQL数据库中有如下六种触发器:

    • Before Insert
    • After Insert
    • Before Update
    • After Update
    • Before Delete
    • After Delete

    常用SQL语句

    SQL语句主要分为哪几类

    数据定义语言DDL(Data Ddefinition Language)CREATE,DROP,ALTER

    主要为以上操作 即对逻辑结构等有操作的,其中包括表结构,视图和索引。

    数据查询语言DQL(Data Query Language)SELECT

    这个较为好理解 即查询操作,以select关键字。各种简单查询,连接查询等 都属于DQL。

    数据操纵语言DML(Data Manipulation Language)INSERT,UPDATE,DELETE

    主要为以上操作 即对数据进行操作的,对应上面所说的查询操作 DQL与DML共同构建了多数初级程序员常用的增删改查操作。而查询是较为特殊的一种 被划分到DQL中。

    数据控制功能DCL(Data Control Language)GRANT,REVOKE,COMMIT,ROLLBACK

    主要为以上操作 即对数据库安全性完整性等有操作的,可以简单的理解为权限控制等。

    超键、候选键、主键、外键分别是什么?

    • 超键:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。
    • 候选键:是最小超键,即没有冗余元素的超键。
    • 主键:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。
    • 外键:在一个表中存在的另一个表的主键称此表的外键。

    SQL 约束有哪几种?

    SQL 约束有哪几种?

    • NOT NULL: 用于控制字段的内容一定不能为空(NULL)。
    • UNIQUE: 控件字段内容不能重复,一个表允许有多个 Unique 约束。
    • PRIMARY KEY: 也是用于控件字段内容不能重复,但它在一个表只允许出现一个。
    • FOREIGN KEY: 用于预防破坏表之间连接的动作,也能防止非法数据插入外键列,因为它必须是它指向的那个表中的值之一。
    • CHECK: 用于控制字段的值范围。

    六种关联查询

    • 交叉连接(CROSS JOIN)
    • 内连接(INNER JOIN)
    • 外连接(LEFT JOIN/RIGHT JOIN)
    • 联合查询(UNION与UNION ALL)
    • 全连接(FULL JOIN)
    • 交叉连接(CROSS JOIN)
    SELECT * FROM A,B(,C)或者SELECT * FROM A CROSS JOIN B (CROSS JOIN C)#没有任何关联条件,结果是笛卡尔积,结果集会很大,没有意义,很少使用内连接(INNER JOIN)SELECT * FROM A,B WHERE A.id=B.id或者SELECT * FROM A INNER JOIN B ON A.id=B.id多表中同时符合某种条件的数据记录的集合,INNER JOIN可以缩写为JOIN
    

    内连接分为三类

    • 等值连接:ON A.id=B.id
    • 不等值连接:ON A.id > B.id
    • 自连接:SELECT * FROM A T1 INNER JOIN A T2 ON T1.id=T2.pid

    外连接(LEFT JOIN/RIGHT JOIN)

    • 左外连接:LEFT OUTER JOIN, 以左表为主,先查询出左表,按照ON后的关联条件匹配右表,没有匹配到的用NULL填充,可以简写成LEFT JOIN
    • 右外连接:RIGHT OUTER JOIN, 以右表为主,先查询出右表,按照ON后的关联条件匹配左表,没有匹配到的用NULL填充,可以简写成RIGHT JOIN

    联合查询(UNION与UNION ALL)

    SELECT * FROM A UNION SELECT * FROM B UNION ...
    
    • 就是把多个结果集集中在一起,UNION前的结果为基准,需要注意的是联合查询的列数要相等,相同的记录行会合并
    • 如果使用UNION ALL,不会合并重复的记录行
    • 效率 UNION 高于 UNION ALL

    全连接(FULL JOIN)

    • MySQL不支持全连接
    • 可以使用LEFT JOIN 和UNION和RIGHT JOIN联合使用
    SELECT * FROM A LEFT JOIN B ON A.id=B.id UNIONSELECT * FROM A RIGHT JOIN B ON A.id=B.id
    

    表连接面试题

    有2张表,1张R、1张S,R表有ABC三列,S表有CD两列,表中各有三条记录。

    R表

    A B C
    a1 b1 c1
    a2 b2 c2
    a3 b3 c3

    S表

    C D
    c1 d1
    c2 d2
    c4 d3
    1. 交叉连接(笛卡尔积):

    select r.*,s.* from r,s

    A B C C D
    a1 b1 c1 c1 d1
    a2 b2 c2 c1 d1
    a3 b3 c3 c1 d1
    a1 b1 c1 c2 d2
    a2 b2 c2 c2 d2
    a3 b3 c3 c2 d2
    a1 b1 c1 c4 d3
    a2 b2 c2 c4 d3
    a3 b3 c3 c4 d3
    1. 内连接结果:

      select r.*,s.* from r inner join s on r.c=s.c

    A B C C D
    a1 b1 c1 c1 d1
    a2 b2 c2 c2 d2
    1. 左连接结果:

      select r.*,s.* from r left join s on r.c=s.c

    A B C C D
    a1 b1 c1 c1 d1
    a2 b2 c2 c2 d2
    a3 b3 c3
    1. 右连接结果:

      select r.*,s.* from r right join s on r.c=s.c

    A B C C D
    a1 b1 c1 c1 d1
    a2 b2 c2 c2 d2
    c4 d3
    1. 全表连接的结果(MySql不支持,Oracle支持):

      select r.*,s.* from r full join s on r.c=s.c

    A B C C D
    a1 b1 c1 c1 d1
    a2 b2 c2 c2 d2
    a3 b3 c3
    c4 d3

    什么是子查询

    1. 条件:一条SQL语句的查询结果做为另一条查询语句的条件或查询结果

    2. 嵌套:多条SQL语句嵌套使用,内部的SQL查询语句称为子查询。

    子查询的三种情况

    1. 子查询是单行单列的情况:结果集是一个值,父查询使用:=、 <、 > 等运算符
    -- 查询工资最高的员工是谁? 
    select  * from employee where salary=(select max(salary) from employee);   
    
    1. 子查询是多行单列的情况:结果集类似于一个数组,父查询使用:in 运算符
    -- 查询工资最高的员工是谁? 
    select  * from employee where salary=(select max(salary) from employee);    
    
    1. 子查询是多行多列的情况:结果集类似于一张虚拟表,不能用于where条件,用于select子句中做为子表
    -- 1) 查询出2011年以后入职的员工信息
    -- 2) 查询所有的部门信息,与上面的虚拟表中的信息比对,找出所有部门ID相等的员工。
    select * from dept d,  (select * from employee where join_date > '2011-1-1') e where e.dept_id =  d.id;    
    
    -- 使用表连接:
    select d.*, e.* from  dept d inner join employee e on d.id = e.dept_id where e.join_date >  '2011-1-1'  
    

    mysql中 in 和 exists 区别

    mysql中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。一直大家都认为exists比in语句的效率要高,这种说法其实是不准确的。这个是要区分环境的。

    1. 如果查询的两个表大小相当,那么用in和exists差别不大。
    2. 如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in。
    3. not in 和not exists:如果查询语句使用了not in,那么内外表都进行全表扫描,没有用到索引;而not extsts的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。

    varchar与char的区别

    char的特点

    • char表示定长字符串,长度是固定的;

    • 如果插入数据的长度小于char的固定长度时,则用空格填充;

    • 因为长度固定,所以存取速度要比varchar快很多,甚至能快50%,但正因为其长度固定,所以会占据多余的空间,是空间换时间的做法;

    • 对于char来说,最多能存放的字符个数为255,和编码无关

    varchar的特点

    • varchar表示可变长字符串,长度是可变的;

    • 插入的数据是多长,就按照多长来存储;

    • varchar在存取方面与char相反,它存取慢,因为长度不固定,但正因如此,不占据多余的空间,是时间换空间的做法;

    • 对于varchar来说,最多能存放的字符个数为65532

    总之,结合性能角度(char更快)和节省磁盘空间角度(varchar更小),具体情况还需具体来设计数据库才是妥当的做法。

    varchar(50)中50的涵义

    最多存放50个字符,varchar(50)和(200)存储hello所占空间一样,但后者在排序时会消耗更多内存,因为order by col采用fixed_length计算col长度(memory引擎也一样)。在早期 MySQL 版本中, 50 代表字节数,现在代表字符数。

    int(20)中20的涵义

    是指显示字符的长度。20表示最大显示宽度为20,但仍占4字节存储,存储范围不变;

    不影响内部存储,只是影响带 zerofill 定义的 int 时,前面补多少个 0,易于报表展示

    mysql为什么这么设计

    对大多数应用没有意义,只是规定一些工具用来显示字符的个数;int(1)和int(20)存储和计算均一样;

    mysql中int(10)和char(10)以及varchar(10)的区别

    • int(10)的10表示显示的数据的长度,不是存储数据的大小;chart(10)和varchar(10)的10表示存储数据的大小,即表示存储多少个字符。

      int(10) 10位的数据长度 9999999999,占32个字节,int型4位
      char(10) 10位固定字符串,不足补空格 最多10个字符
      varchar(10) 10位可变字符串,不足补空格 最多10个字符

    • char(10)表示存储定长的10个字符,不足10个就用空格补齐,占用更多的存储空间

    • varchar(10)表示存储10个变长的字符,存储多少个就是多少个,空格也按一个字符存储,这一点是和char(10)的空格不同的,char(10)的空格表示占位不算一个字符

    FLOAT和DOUBLE的区别是什么?

    • FLOAT类型数据可以存储至多8位十进制数,并在内存中占4字节。
    • DOUBLE类型数据可以存储至多18位十进制数,并在内存中占8字节。

    drop、delete与truncate的区别

    三者都表示删除,但是三者有一些差别:

    Delete Truncate Drop
    类型 属于DML 属于DDL 属于DDL
    回滚 可回滚 不可回滚 不可回滚
    删除内容 表结构还在,删除表的全部或者一部分数据行 表结构还在,删除表中的所有数据 从数据库中删除表,所有的数据行,索引和权限也会被删除
    删除速度 删除速度慢,需要逐行删除 删除速度快 删除速度最快

    因此,在不再需要一张表的时候,用drop;在想删除部分数据行时候,用delete;在保留表而删除所有数据的时候用truncate。

    UNION与UNION ALL的区别?

    • 如果使用UNION ALL,不会合并重复的记录行
    • 效率 UNION 高于 UNION ALL

    SQL优化

    如何定位及优化SQL语句的性能问题?创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

    对于低性能的SQL语句的定位,最重要也是最有效的方法就是使用执行计划,MySQL提供了explain命令来查看语句的执行计划。 我们知道,不管是哪种数据库,或者是哪种数据库引擎,在对一条SQL语句进行执行的过程中都会做很多相关的优化,对于查询语句,最重要的优化方式就是使用索引。 而执行计划,就是显示数据库引擎对于SQL语句的执行的详细情况,其中包含了是否使用索引,使用什么索引,使用的索引的相关信息等

    在这里插入图片描述

    执行计划包含的信息 id 有一组数字组成。表示一个查询中各个子查询的执行顺序;

    • id相同执行顺序由上至下。
    • id不同,id值越大优先级越高,越先被执行。
    • id为null时表示一个结果集,不需要使用它查询,常出现在包含union等查询语句中。

    select_type 每个子查询的查询类型,一些常见的查询类型。

    id select_type description
    1 SIMPLE 不包含任何子查询或union等查询
    2 PRIMARY 包含子查询最外层查询就显示为 PRIMARY
    3 SUBQUERY 在select或 where字句中包含的查询
    4 DERIVED from字句中包含的查询
    5 UNION 出现在union后的查询语句中
    6 UNION RESULT 从UNION中获取结果集,例如上文的第三个例子

    table 查询的数据表,当从衍生表中查数据时会显示 x 表示对应的执行计划id partitions 表分区、表创建的时候可以指定通过那个列进行表分区。 举个例子:

    create table tmp (
        id int unsigned not null AUTO_INCREMENT,
        name varchar(255),
        PRIMARY KEY (id)
    ) engine = innodb
    partition by key (id) partitions 5;
    

    type(非常重要,可以看到有没有走索引) 访问类型

    • ALL 扫描全表数据
    • index 遍历索引
    • range 索引范围查找
    • index_subquery 在子查询中使用 ref
    • unique_subquery 在子查询中使用 eq_ref
    • ref_or_null 对Null进行索引的优化的 ref
    • fulltext 使用全文索引
    • ref 使用非唯一索引查找数据
    • eq_ref 在join查询中使用PRIMARY KEYorUNIQUE NOT NULL索引关联。

    possible_keys 可能使用的索引,注意不一定会使用。查询涉及到的字段上若存在索引,则该索引将被列出来。当该列为 NULL时就要考虑当前的SQL是否需要优化了。

    key 显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL。

    TIPS:查询中若使用了覆盖索引(覆盖索引:索引的数据覆盖了需要查询的所有数据),则该索引仅出现在key列表中

    key_length 索引长度

    ref 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

    rows 返回估算的结果集数目,并不是一个准确的值。

    extra 的信息非常丰富,常见的有:

    1. Using index 使用覆盖索引
    2. Using where 使用了用where子句来过滤结果集
    3. Using filesort 使用文件排序,使用非索引列进行排序时出现,非常消耗性能,尽量优化。
    4. Using temporary 使用了临时表 sql优化的目标可以参考阿里开发手册
    【推荐】SQL性能优化的目标:至少要达到 range 级别,要求是ref级别,如果可以是consts最好。 
    说明: 
    1) consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。 
    2) ref 指的是使用普通的索引(normal index)。 
    3) range 对索引进行范围检索。 
    反例:explain表的结果,type=index,索引物理文件全扫描,速度非常慢,这个index级别比较range还低,与全表扫描是小巫见大巫。
    

    SQL的生命周期?

    1. 应用服务器与数据库服务器建立一个连接

    2. 数据库进程拿到请求sql

    3. 解析并生成执行计划,执行

    4. 读取数据到内存并进行逻辑处理

    5. 通过步骤一的连接,发送结果到客户端

    6. 关掉连接,释放资源

      在这里插入图片描述

    大表数据查询,怎么优化

    1. 优化shema、sql语句+索引;
    2. 第二加缓存,memcached, redis;
    3. 主从复制,读写分离;
    4. 垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
    5. 水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;

    超大分页怎么处理?

    超大的分页一般从两个方向上来解决.

    • 数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于select * from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age > 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以select * from table where id > 1000000 limit 10,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据.
    • 从需求的角度减少这种请求…主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.

    解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可.

    在阿里巴巴《Java开发手册》中,对超大分页的解决办法是类似于上面提到的第一种.

    【推荐】利用延迟关联或者子查询优化超多分页场景。 
    
    说明:MySQL并不是跳过offset行,而是取offset+N行,然后返回放弃前offset行,返回N行,那当offset特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行SQL改写。 
    
    正例:先快速定位需要获取的id段,然后再关联: 
    
    SELECT a.* FROM1 a, (select id from1 where 条件 LIMIT 100000,20 ) b where a.id=b.id
    

    mysql 分页

    LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1)

    mysql> SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15 
    

    为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:

    mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last. 
    

    如果只给定一个参数,它表示返回最大的记录行数目:

    mysql> SELECT * FROM table LIMIT 5; //检索前 5 个记录行 
    

    换句话说,LIMIT n 等价于 LIMIT 0,n。

    慢查询日志

    用于记录执行时间超过某个临界值的SQL日志,用于快速定位慢查询,为我们的优化做参考。

    开启慢查询日志

    配置项:slow_query_log

    可以使用show variables like ‘slov_query_log’查看是否开启,如果状态值为OFF,可以使用set GLOBAL slow_query_log = on来开启,它会在datadir下产生一个xxx-slow.log的文件。

    设置临界时间

    配置项:long_query_time

    查看:show VARIABLES like 'long_query_time',单位秒

    设置:set long_query_time=0.5

    实操时应该从长时间设置到短的时间,即将最慢的SQL优化掉

    查看日志,一旦SQL超过了我们设置的临界时间就会被记录到xxx-slow.log

    关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

    在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。

    慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?

    所以优化也是针对这三个方向来的,

    • 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。
    • 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。
    • 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

    为什么要尽量设定一个主键?

    主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键。设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全。

    主键使用自增ID还是UUID?

    推荐使用自增ID,不要使用UUID。

    因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降。

    总之,在数据量大一些的情况下,用自增主键性能会好一些。

    关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键。

    字段为什么要求定义为not null?

    null值会占用更多的字节,且会在程序中造成很多与预期不符的情况。

    如果要存储用户的密码散列,应该使用什么字段进行存储?

    密码散列,盐,用户身份证号等固定长度的字符串应该使用char而不是varchar来存储,这样可以节省空间且提高检索效率。

    优化查询过程中的数据访问

    • 访问数据太多导致查询性能下降
    • 确定应用程序是否在检索大量超过需要的数据,可能是太多行或列
    • 确认MySQL服务器是否在分析大量不必要的数据行
    • 避免犯如下SQL语句错误
    • 查询不需要的数据。解决办法:使用limit解决
    • 多表关联返回全部列。解决办法:指定列名
    • 总是返回全部列。解决办法:避免使用SELECT *
    • 重复查询相同的数据。解决办法:可以缓存数据,下次直接读取缓存
    • 是否在扫描额外的记录。解决办法:
    • 使用explain进行分析,如果发现查询需要扫描大量的数据,但只返回少数的行,可以通过如下技巧去优化:
    • 使用索引覆盖扫描,把所有的列都放到索引中,这样存储引擎不需要回表获取对应行就可以返回结果。
    • 改变数据库和表的结构,修改数据表范式
    • 重写SQL语句,让优化器可以以更优的方式执行查询。

    优化长难的查询语句

    • 一个复杂查询还是多个简单查询
    • MySQL内部每秒能扫描内存中上百万行数据,相比之下,响应数据给客户端就要慢得多
    • 使用尽可能小的查询是好的,但是有时将一个大的查询分解为多个小的查询是很有必要的。
    • 切分查询
    • 将一个大的查询分为多个小的相同的查询
    • 一次性删除1000万的数据要比一次删除1万,暂停一会的方案更加损耗服务器开销。
    • 分解关联查询,让缓存的效率更高。
    • 执行单个查询可以减少锁的竞争。
    • 在应用层做关联更容易对数据库进行拆分。
    • 查询效率会有大幅提升。
    • 较少冗余记录的查询。

    优化特定类型的查询语句

    • count(*)会忽略所有的列,直接统计所有列数,不要使用count(列名)
    • MyISAM中,没有任何where条件的count(*)非常快。
    • 当有where条件时,MyISAM的count统计不一定比其它引擎快。
    • 可以使用explain查询近似值,用近似值替代count(*)
    • 增加汇总表
    • 使用缓存

    优化关联查询

    • 确定ON或者USING子句中是否有索引。
    • 确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引。

    优化子查询

    • 用关联查询替代
    • 优化GROUP BY和DISTINCT
    • 这两种查询据可以使用索引来优化,是最有效的优化方法
    • 关联查询中,使用标识列分组的效率更高
    • 如果不需要ORDER BY,进行GROUP BY时加ORDER BY NULL,MySQL不会再进行文件排序。
    • WITH ROLLUP超级聚合,可以挪到应用程序处理

    优化LIMIT分页

    • LIMIT偏移量大的时候,查询效率较低
    • 可以记录上次查询的最大ID,下次查询时直接根据该ID来查询

    优化UNION查询

    • UNION ALL的效率高于UNION

    优化WHERE子句

    解题方法

    对于此类考题,先说明如何定位低效SQL语句,然后根据SQL语句可能低效的原因做排查,先从索引着手,如果索引没有问题,考虑以上几个方面,数据访问的问题,长难查询句的问题还是一些特定类型优化的问题,逐一回答。

    SQL语句优化的一些方法?

    • 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
    • 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
    select id from t where num is null
    -- 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
    select id from t where num=
    
    • 3.应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
    • 4.应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
    select id from t where num=10 or num=20
    -- 可以这样查询:
    select id from t where num=10 union all select id from t where num=20
    
    • 5.in 和 not in 也要慎用,否则会导致全表扫描,如:
    select id from t where num in(1,2,3) 
    -- 对于连续的数值,能用 between 就不要用 in 了:
    select id from t where num between 1 and 3
    
    • 6.下面的查询也将导致全表扫描:select id from t where name like ‘%李%’若要提高效率,可以考虑全文检索。
    • 7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
    select id from t where num=@num
    -- 可以改为强制查询使用索引:
    select id from t with(index(索引名)) where num=@num
    
    • 8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    select id from t where num/2=100
    -- 应改为:
    select id from t where num=100*2
    
    • 9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
    select id from t where substring(name,1,3)=’abc’
    -- name以abc开头的id应改为:
    select id from t where name like ‘abc%
    • 10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

    数据库优化

    为什么要优化

    • 系统的吞吐量瓶颈往往出现在数据库的访问速度上
    • 随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢
    • 数据是存放在磁盘上的,读写速度无法和内存相比

    优化原则:减少系统瓶颈,减少资源占用,增加系统的反应速度。

    数据库结构优化

    一个好的数据库设计方案对于数据库的性能往往会起到事半功倍的效果。

    需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。

    将字段很多的表分解成多个表

    对于字段较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。

    因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。

    增加中间表

    对于需要经常联合查询的表,可以建立中间表以提高查询效率。

    通过建立中间表,将需要通过联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询。

    增加冗余字段

    设计数据表时应尽量遵循范式理论的规约,尽可能的减少冗余字段,让数据库设计看起来精致、优雅。但是,合理的加入冗余字段可以提高查询速度。

    表的规范化程度越高,表和表之间的关系越多,需要连接查询的情况也就越多,性能也就越差。

    注意:

    冗余字段的值在一个表中修改了,就要想办法在其他表中更新,否则就会导致数据不一致的问题。

    MySQL数据库cpu飙升到500%的话他怎么处理?

    当 cpu 飙升到 500%时,先用操作系统命令 top 命令观察是不是 mysqld 占用导致的,如果不是,找出占用高的进程,并进行相关处理。

    如果是 mysqld 造成的, show processlist,看看里面跑的 session 情况,是不是有消耗资源的 sql 在运行。找出消耗高的 sql,看看执行计划是否准确, index 是否缺失,或者实在是数据量太大造成。

    一般来说,肯定要 kill 掉这些线程(同时观察 cpu 使用率是否下降),等进行相应的调整(比如说加索引、改 sql、改内存参数)之后,再重新跑这些 SQL。

    也有可能是每个 sql 消耗资源并不多,但是突然之间,有大量的 session 连进来导致 cpu 飙升,这种情况就需要跟应用一起来分析为何连接数会激增,再做出相应的调整,比如说限制连接数等

    大表怎么优化?某个表有近千万数据,CRUD比较慢,如何优化?分库分表了是怎么做的?分表分库了有什么问题?有用到中间件么?他们的原理知道么?

    当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:

    1. 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。;
    2. 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
    3. 缓存: 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存;

    还有就是通过分库分表的方式进行优化,主要有垂直分表和水平分表

    1. 垂直分区:

      根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。

      简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。 如下图所示,这样来说大家应该就更容易理解了。

      img

      垂直拆分的优点: 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。

      垂直拆分的缺点: 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;

      垂直分表

      把主键和一些列放在一个表,然后把主键和另外的列放在另一个表中

      img

      适用场景
      • 1、如果一个表中某些列常用,另外一些列不常用
      • 2、可以使数据行变小,一个数据页能存储更多数据,查询时减少I/O次数
      缺点
      • 有些分表的策略基于应用层的逻辑算法,一旦逻辑算法改变,整个分表逻辑都会改变,扩展性较差
      • 对于应用层来说,逻辑算法增加开发成本
      • 管理冗余列,查询所有数据需要join操作
    2. 水平分区:

      保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。

      水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。

      数据库水平拆分

      水品拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 水平拆分最好分库

      水平拆分能够 支持非常大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨界点Join性能较差,逻辑复杂。

      《Java工程师修炼之道》的作者推荐 尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。

      水平分表:

      表很大,分割后可以降低在查询时需要读的数据和索引的页数,同时也降低了索引的层数,提高查询次数

      img

      适用场景
      • 1、表中的数据本身就有独立性,例如表中分表记录各个地区的数据或者不同时期的数据,特别是有些数据常用,有些不常用。
      • 2、需要把数据存放在多个介质上。
      水平切分的缺点
      • 1、给应用增加复杂度,通常查询时需要多个表名,查询所有数据都需UNION操作
      • 2、在许多数据库应用中,这种复杂度会超过它带来的优点,查询时会增加读一个索引层的磁盘次数

      下面补充一下数据库分片的两种常见方案:

      • 客户端代理: 分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。 当当网的 Sharding-JDBC 、阿里的TDDL是两种比较常用的实现。
      • 中间件代理: 在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。 我们现在谈的 Mycat 、360的Atlas、网易的DDB等等都是这种架构的实现。

    分库分表后面临的问题

    • 事务支持 分库分表后,就成了分布式事务了。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价; 如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。

    • 跨库join

      只要是进行切分,跨节点Join的问题是不可避免的。但是良好的设计和切分却可以减少此类情况的发生。解决这一问题的普遍做法是分两次查询实现。在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求得到关联数据。 分库分表方案产品

    • 跨节点的count,order by,group by以及聚合函数问题 这些是一类问题,因为它们都需要基于全部数据集合进行计算。多数的代理都不会自动处理合并工作。解决方案:与解决跨节点join问题的类似,分别在各个节点上得到结果后在应用程序端进行合并。和join不同的是每个结点的查询可以并行执行,因此很多时候它的速度要比单一大表快很多。但如果结果集很大,对应用程序内存的消耗是一个问题。

    • 数据迁移,容量规划,扩容等问题 来自淘宝综合业务平台团队,它利用对2的倍数取余具有向前兼容的特性(如对4取余得1的数对2取余也是1)来分配数据,避免了行级别的数据迁移,但是依然需要进行表级别的迁移,同时对扩容规模和分表数量都有限制。总得来说,这些方案都不是十分的理想,多多少少都存在一些缺点,这也从一个侧面反映出了Sharding扩容的难度。

    • ID问题

    • 一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键生成机制。一方面,某个分区数据库自生成的ID无法保证在全局上是唯一的;另一方面,应用程序在插入数据之前需要先获得ID,以便进行SQL路由. 一些常见的主键生成策略

    UUID 使用UUID作主键是最简单的方案,但是缺点也是非常明显的。由于UUID非常的长,除占用大量存储空间外,最主要的问题是在索引上,在建立索引和基于索引进行查询时都存在性能问题。 Twitter的分布式自增ID算法Snowflake 在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位 机器ID 10位 毫秒内序列12位。

    • 跨分片的排序分页

      般来讲,分页时需要按照指定字段进行排序。当排序字段就是分片字段的时候,我们通过分片规则可以比较容易定位到指定的分片,而当排序字段非分片字段的时候,情况就会变得比较复杂了。为了最终结果的准确性,我们需要在不同的分片节点中将数据进行排序并返回,并将不同分片返回的结果集进行汇总和再次排序,最后再返回给用户。如下图所示:

      在这里插入图片描述

    MySQL的复制原理以及流程

    主从复制:将主数据库中的DDL和DML操作通过二进制日志(BINLOG)传输到从数据库上,然后将这些日志重新执行(重做);从而使得从数据库的数据与主数据库保持一致。

    主从复制的作用

    1. 主数据库出现问题,可以切换到从数据库。
    2. 可以进行数据库层面的读写分离。
    3. 可以在从数据库上进行日常备份。

    MySQL主从复制解决的问题

    • 数据分布:随意开始或停止复制,并在不同地理位置分布数据备份
    • 负载均衡:降低单个服务器的压力
    • 高可用和故障切换:帮助应用程序避免单点失败
    • 升级测试:可以用更高版本的MySQL作为从库

    MySQL主从复制工作原理

    • 在主库上把数据更高记录到二进制日志
    • 从库将主库的日志复制到自己的中继日志
    • 从库读取中继日志的事件,将其重放到从库数据中

    基本原理流程,3个线程以及之间的关联

    :binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;

    :io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进自己的relay log中;

    :sql执行线程——执行relay log中的语句;

    复制过程

    img

    Binary log:主数据库的二进制日志

    Relay log:从服务器的中继日志

    第一步:master在每个事务更新数据完成之前,将该操作记录串行地写入到binlog文件中。

    第二步:salve开启一个I/O Thread,该线程在master打开一个普通连接,主要工作是binlog dump process。如果读取的进度已经跟上了master,就进入睡眠状态并等待master产生新的事件。I/O线程最终的目的是将这些事件写入到中继日志中。

    第三步:SQL Thread会读取中继日志,并顺序执行该日志中的SQL事件,从而与主数据库中的数据保持一致。

    读写分离有哪些解决方案?

    读写分离是依赖于主从复制,而主从复制又是为读写分离服务的。因为主从复制要求slave不能写只能读(如果对slave执行写操作,那么show slave status将会呈现Slave_SQL_Running=NO,此时你需要按照前面提到的手动同步一下slave)。

    方案一

    使用mysql-proxy代理

    优点:直接实现读写分离和负载均衡,不用修改代码,master和slave用一样的帐号,mysql官方不建议实际生产中使用

    缺点:降低性能, 不支持事务

    方案二

    使用AbstractRoutingDataSource+aop+annotation在dao层决定数据源。
    如果采用了mybatis, 可以将读写分离放在ORM层,比如mybatis可以通过mybatis plugin拦截sql语句,所有的insert/update/delete都访问master库,所有的select 都访问salve库,这样对于dao层都是透明。 plugin实现时可以通过注解或者分析语句是读写方法来选定主从库。不过这样依然有一个问题, 也就是不支持事务, 所以我们还需要重写一下DataSourceTransactionManager, 将read-only的事务扔进读库, 其余的有读有写的扔进写库。

    方案三

    使用AbstractRoutingDataSource+aop+annotation在service层决定数据源,可以支持事务.

    缺点:类内部方法通过this.xx()方式相互调用时,aop不会进行拦截,需进行特殊处理。

    备份计划,mysqldump以及xtranbackup的实现原理

    (1)备份计划

    视库的大小来定,一般来说 100G 内的库,可以考虑使用 mysqldump 来做,因为 mysqldump更加轻巧灵活,备份时间选在业务低峰期,可以每天进行都进行全量备份(mysqldump 备份出来的文件比较小,压缩之后更小)。

    100G 以上的库,可以考虑用 xtranbackup 来做,备份速度明显要比 mysqldump 要快。一般是选择一周一个全备,其余每天进行增量备份,备份时间为业务低峰期。

    (2)备份恢复时间

    物理备份恢复快,逻辑备份恢复慢

    这里跟机器,尤其是硬盘的速率有关系,以下列举几个仅供参考

    20G的2分钟(mysqldump)

    80G的30分钟(mysqldump)

    111G的30分钟(mysqldump)

    288G的3小时(xtra)

    3T的4小时(xtra)

    逻辑导入时间一般是备份时间的5倍以上

    (3)备份恢复失败如何处理

    首先在恢复之前就应该做足准备工作,避免恢复的时候出错。比如说备份之后的有效性检查、权限检查、空间检查等。如果万一报错,再根据报错的提示来进行相应的调整。

    (4)mysqldump和xtrabackup实现原理

    mysqldump

    mysqldump 属于逻辑备份。加入–single-transaction 选项可以进行一致性备份。后台进程会先设置 session 的事务隔离级别为 RR(SET SESSION TRANSACTION ISOLATION LEVELREPEATABLE READ),之后显式开启一个事务(START TRANSACTION /*!40100 WITH CONSISTENTSNAPSHOT */),这样就保证了该事务里读到的数据都是事务事务时候的快照。之后再把表的数据读取出来。如果加上–master-data=1 的话,在刚开始的时候还会加一个数据库的读锁(FLUSH TABLES WITH READ LOCK),等开启事务后,再记录下数据库此时 binlog 的位置(showmaster status),马上解锁,再读取表的数据。等所有的数据都已经导完,就可以结束事务

    Xtrabackup:

    xtrabackup 属于物理备份,直接拷贝表空间文件,同时不断扫描产生的 redo 日志并保存下来。最后完成 innodb 的备份后,会做一个 flush engine logs 的操作(老版本在有 bug,在5.6 上不做此操作会丢数据),确保所有的 redo log 都已经落盘(涉及到事务的两阶段提交

    概念,因为 xtrabackup 并不拷贝 binlog,所以必须保证所有的 redo log 都落盘,否则可能会丢最后一组提交事务的数据)。这个时间点就是 innodb 完成备份的时间点,数据文件虽然不是一致性的,但是有这段时间的 redo 就可以让数据文件达到一致性(恢复的时候做的事

    情)。然后还需要 flush tables with read lock,把 myisam 等其他引擎的表给备份出来,备份完后解锁。这样就做到了完美的热备。

    数据表损坏的修复方式有哪些?

    使用 myisamchk 来修复,具体步骤:

    • 1)修复前将mysql服务停止。
    • 2)打开命令行方式,然后进入到mysql的/bin目录。
    • 3)执行myisamchk –recover 数据库所在路径/*.MYI

    使用repair table 或者 OPTIMIZE table命令来修复,REPAIR TABLE table_name 修复表 OPTIMIZE TABLE table_name 优化表 REPAIR TABLE 用于修复被破坏的表。 OPTIMIZE TABLE 用于回收闲置的数据库空间,当表上的数据行被删除时,所占据的磁盘空间并没有立即被回收,使用了OPTIMIZE TABLE命令后这些空间将被回收,并且对磁盘上的数据行进行重排(注意:是磁盘上,而非数据库)

    展开全文
  • 达梦数据库功能特性

    千次阅读 2020-05-07 21:51:14
    DM8 是达梦数据库有限公司推出的新一代高性能数据库产品。它具有开放的、可扩展 的体系结构,易于使用的事务处理系统,以及低廉的维护成本,是达梦公司完全自主开发的 产品。DM8 以 RDBMS 为核心,以 SQL 为标准,是...

    DM8 是达梦数据库有限公司推出的新一代高性能数据库产品。它具有开放的、可扩展
    的体系结构,易于使用的事务处理系统,以及低廉的维护成本,是达梦公司完全自主开发的
    产品。DM8 以 RDBMS 为核心,以 SQL 为标准,是一个能跨越多种软硬件平台、具有大型
    数据综合管理能力的、高效稳定的通用数据库管理系统。
    数据库访问是数据库应用系统中非常重要的组成部分。DM 作为一个通用数据库管理系
    统,提供了多种数据库访问接口,包括 ODBC、JDBC、DPI、OLEDB 以及嵌入方式等。本
    书详细介绍了 DM 的各种访问接口,相应开发环境的配置,以及一些开发用例。
    本书的主要读者是从事过数据库应用系统开发,并具有 SQL 使用基础的程序员。
    开发一个应用系统,需要对其使用的数据库管理系统所具有的功能、性能、特性有较深
    入的了解。DM 作为一个通用的数据库管理系统,具有非常丰富的功能和特色。
    功能特性
    DM 除了具备一般 DBMS 所应具有的基本功能外,还特别具有以下特性:

    1. 通用性;
    2. 高性能;
    3. 高安全性;
    4. 高可靠、高可用性;
    5. 易用性;
    6. 海量数据存储和管理;
    7. 全文索引;
    8. 对存储模块的支持;
    9. 对 WEB 应用的支持。
      以下对这些特性做具体介绍。
      通用性
      DM 是大型通用数据库管理系统,其通用性主要表现在以下四个方面:
    10. SQL 及接口的开发符合国际通用标准
      符合 SQL92/SQL99、ODBC、JDBC、OLE DB、PHP、.NET Provider 等国际标准或行
      业标准,提供所有数据库标准接口;
      支持 SQL92 标准的所有数据类型;
      SQL92 入门级标准符合率达到 100%,过渡级也达到 100%;
      提供了符合 ODBC 3.0 标准的 ODBC 接口驱动程序、符合 JDBC 3.0 标准的 JDBC 接口
      驱动程序和符合 OLE DB 2.7 标准的 OLE DB 接口驱动程序。
      支持 eclipse、JBuilder、Visual Studio、Delphi、C++Builder、PowerBuilder 等各种流行
      的数据库应用开发工具。
      此外,为了提高数据库的通用性,DM 还增加了一些其他数据库的数据类型、函数和语

    概述
    法等特性,与国外数据库管理系统(如 Oracle、SQL Server 等)高度兼容,如:同时支持自
    增列和序列。而且从数据库市场现状和技术人员开发习惯的角度出发,注重在功能扩展、函
    数配备、调用接口及调用方式等方面尽量与国际主流的各类数据库产品接轨,提高应用系统
    的可移植性和可重用性,降低开发厂商移植和升级的工作难度和强度。
    .跨平台支持
    DM 服务器内核采用一套源代码实现了对不同软件( WINDOWS/LINUX/UNIX
    /AIX/SOLARIS 等)、硬件(X64/X86/SPARC/POWER/TITAM)平台的支持,各种平台上的
    数据存储结构完全一致。与此同时,各平台的消息通信结构也完全保持一致,使得达梦数据
    库的各种组件均可以跨不同的软、硬件平台与数据库服务器进行交互。
    DM 支持 WINDOWS 2000/XP/2003、2.4 及 2.4 以上内核的 LINUX(Redhat、Debian、
    Suse、红旗、中标等)、麒麟操作系统(Kylin)、AIX、SOLARIS 等国内外常用操作系统。
    DM 的管理工具、应用开发工具集使用 Java 编写,从而可以跨平台工作,即同一程序
    无需重新编译,将其执行码拷贝到任一种操作系统平台上都能直接运行。这也保证了它们在
    各种操作系统平台上都有统一的界面风格。
    DM 产品采用一致的人机交互界面,既有易于操作使用的图形化界面工具,也有丰富的
    命令行控制台工具。
    支持对称多处理机系统
    由于 DM 核心系统的多线程机制利用了操作系统的线程调度,因此系统的工作线程在
    单 CPU 和多 CPU 机器上都能很好地并行操作。对于多 CPU 的系统,只要采用的操作系统
    支持多 CPU 机制,DM 就能很好地实现多 CPU 协同工作。
    对 UNICODE 的支持
    目前 DM 系统支持了 Unicode 字符集和其他多种字符集。用户可以在安装 DM 系统时,
    指定服务器端使用 UTF8 字符集。此时在客户端,用户能够以各种字符集存储文本,并使用
    系统提供的接口设置客户端使用的字符集,缺省使用客户端操作系统缺省的字符集。客户端
    和服务器端的字符集由用户指定后,所有字符集都可以透明地使用,系统负责不同字符集之
    间的自动转换。
    对 Unicode 的支持使 DM 系统适应国际化的需要,增强了 DM 的通用性。
    高性能
    DM 主要通过以下机制实现了系统的高性能:
    可配置的多工作线程处理功能
    DM 允许用户配置工作线程的数目。工作线程是整个系统所公用的资源,不专门为某个
    特定的连接服务。如果某个数据库操作由于无法取得相应的资源(如锁)而不能继续,将暂
    停当前的数据库事务,相应的工作线程会立即执行其它的数据库请求服务。所以,在系统硬
    件及操作系统性能够满足要求的情况下,连接数和任务请求数的增加对 DM 性能的影响是
    线性的。DM 自动协调工作线程对内存、数据页等物理资源的共享。
    高效的并发控制机制
    DM 提供了数据库的行级和表级的资源封锁机制,大大提高了事务并发访问的数目。
    DM 通过以下几点确保并发控制的高效:
    用 HASH 表管理实现锁管理,能够在系统成千上万的锁中迅速地找到所需的锁;

    利用回滚段保存记录修改前的数据,实现数据的读一致性。
    另外,在 DM 中,当对数据页进行操作时,系统会自动对数据页采用合适的封锁机制。
    同时,DM 也提供了函数供用户自行定义锁定类型,以增强系统并发度,提高系统效率。
    有效的查询优化策略
    DM 采用有效的基于代价的查询优化策略,其查询优化子系统能计算最优的查询路径以
    保证查询的执行效率。查询优化主要通过以下三个步骤进行:
    SQL 转换:DM 首先对用户输入的查询语句进行一系列复杂的转换,其结果为一个
    语义上等价但处理起来更为有效的 SQL 语句;
    统计信息与代价估计:DM 为数据库对象保存了一系列的统计信息,代价估计模块
    基于系统的 I/O、CPU 和内存等资源情况和数据库对象的统计信息估算每个计划的
    代价;
    执行计划选择:执行计划描述了查询语句的每一个处理步骤,如以什么算法执行连
    接,是否使用索引等。优化器考虑可能的执行计划,并选择代价最小的交付执行。
    另外,用户可通过 DM 的客户端工具查看查询语句的执行计划。
    尽可能少的网络通讯量
    DM 对消息发送条件进行仔细判断,避免和减少无用的网络交互,提高了消息处理的效
    率,减轻了服务器的负担,降低了等待时间,加速了工作线程的运转,提高了性能。对于密
    集型联机事务处理效果尤佳。
    加强的缓冲机制
    DM 为了提高系统运行效率,对于频繁操作的对象进行了必要的缓存处理,实现了数据
    字典高速缓冲,实现了语法分析树的可重用,优化了存储过程和触发器的运行。
    与此同时,DM 还新增了动态缓冲区机制。当数据库服务器发现因为缓冲区不足而产生
    频繁的缓冲区页面淘汰时,如果整个系统还有可用内存,则 DM 会自动扩展缓冲区,减少
    淘汰几率,显著提升系统性能。
    针对 64 位计算的优化策略和技术
    DM 在代码级全面支持 64 位系统,能够支持主流 64 位处理机和操作系统,并融入了很
    多针对 64 位计算的优化策略和技术。DM 不仅能够运行在 64 位系统上,还能很好地利用
    64 位系统的资源(例如能充分地利用更大容量的内存),在 64 位系统上表现出良好的性能。
    查询计划重用
    DM 在首次执行 SQL 语句过程中会在内存中创建一个计划缓冲池,缓存执行过的 SQL
    语句、存储过程以及触发器的执行计划。对于后续接收到的 SQL 命令,系统自动采用字符
    串全字匹配的方式,在计划池中查找对应的计划,如果有则直接使用,否则对该语句进行分
    析,创建执行计划,并将执行计划放入计划缓冲池中。通过这种方式,系统可以极大地节省
    对语句进行分析和创建执行计划的时间,从而提升系统性能。
    查询结果集缓存
    DM 还支持查询结果的缓存功能。查询语句第一次执行后,系统可以把结果保存下来,
    如果后面有同样的语句,且所访问的数据没有发生变化,则不需要进行计算,直接把先前保
    存的结果返回给客户即可。在很多以查询为主的系统中,采用该功能性能可以得到成倍地提
    升。
    数据压缩
    DM 新增了数据压缩的功能,用户可以对整个表进行压缩,也可以选择对部分字段进行

    压缩。对于 I/O 密集型的系统来说,通过采取适当的数据压缩的策略,可以减少系统的 I/O
    量,在 I/O 子系统是整个系统的瓶颈时,采取该措施可以有效提升系统性能。
    函数索引
    DM 扩充了索引的建立方法,允许在表达式上面建立索引。表达式既可以出现在函数的
    参数中(如 ABS(ID)),也可以是列的操作(如 C1+C2),DM 把这类索引称为函数索引。函
    数索引的引入为 DBA 提供了一种新的优化手段。
    例如,执行如下的语句:
    SELECT * FROM t WHERE UPPER(name) = ‘CBDG’;
    在以往的版本中,这条语句的执行只能是全表扫描。如果建立如下索引:
    CREATE INDEX i_t_fbi_name ON t(UPPER(name));
    则可以通过函数所以 i_t_fbi_name,进行等值扫描,性能获得大幅提升。
    高安全性
    只具备自主访问控制安全机制的数据库远不能满足一些对安全具有高要求的系统的需
    要。为了保证系统的安全性,DM 采用基于角色与权限的管理方法来实现基本安全功能,并
    根据三权分立的安全机制,将审计和数据库管理分别处理,同时增加了强制访问控制功能,
    另外,还实现了包括通讯加密、存储加密以及资源限制等辅助安全功能,使得达梦数据库安
    全级别达到 B1 级。
    完全自主知识产权
    达梦数据库是具有完全自主知识产权的国产大型数据库管理系统。在产品开发过程中,
    达梦公司始终坚持自主开发的原则,致力于保卫国家信息安全,推进国民经济信息化建设,
    拥有产品的全部源代码和完全的自主版权。这一方面杜绝了继承开源系统导致的版权纠纷,
    同时也从根本上保证了系统的安全性,并有利于与其它应用系统集成,可以根据具体需求定
    制和提供及时有效的服务。
    三权分立的安全机制
    DM 在安全管理方面采用了三权分立的安全管理体制,把系统管理员分为数据库管理员
    DBA、数据库安全管理员 SSO、数据库审计员 AUDITOR 三类。DBA 负责自主访问控制及
    系统维护与管理方面的工作,SSO 负责强制访问控制,AUDITOR 负责系统的审计。这种管
    理体制真正做到三权分立,各行其责,相互制约,更好地实现了数据的保密性、完整性和可
    用性。
    身份验证
    DM 能够根据用户在系统中的登录名和密码确定该用户是否具有登录的权限和其在系
    统中的系统级角色,确定该用户能够做什么和不能够做什么。DM 提供两种身份验证模式来
    保护对服务器访问的安全,即数据库身份验证模式和外部身份验证模式。数据库身份验证模
    式需要利用数据库口令,外部身份验证模式支持基于操作系统(OS)的身份验证。
    资源限制
    资源限制是控制用户对 DM 服务器系统资源的使用情况,以尽可能减少人为的安全隐
    患。通过资源限制可以提供一个规划数据库系统资源使用的接口,可以人为地规划数据库资
    源的分配。这样做对于恶意地抢占资源的访问可以起到有效的遏制,保证普通数据库应用的
    正常进行,同时资源限制还起到保证身份验证可靠性的作用。

    自主访问控制
    DM 系统根据用户的权限执行自主访问控制。用户权限是指用户在数据对象上被允许执
    行的操作。规定用户权限要考虑三个因素:用户、数据对象和操作,即什么用户在哪些数据
    对象上可执行什么操作。所有的用户权限都要记录在系统表(数据字典)中,对用户存取权
    限的定义称为授权,当用户提出操作请求时,DM 根据授权情况进行检查,以决定是执行操
    作还是拒绝执行,从而保证用户能够存取他有权存取的数据,不能存取他无权存取的数据。
    基于标记的强制访问控制
    DM 利用策略和标记来实现数据库的强制访问机制。强制访问控制主要是针对用户和元
    组,用户操作元组时,不仅要满足自主访问控制的权限要求,还要满足用户和元组之间标记
    的相容性。这样,就避免了出现管理权限全部由数据库管理员一人负责的局面,同时也相应
    地增强了系统的安全性。
    数据库审计
    审计机制是 DM 数据库管理系统安全管理的重要组成部分之一。DM 具有一个灵活的审
    计子系统,可以通过它来记录系统级事件、个别用户的行为以及对数据库对象的访问。通过
    查看审计信息,数据库审计员可以知道用户访问的形式以及试图对该系统进行的操作。一旦
    出现问题,数据库审计员可分析审计信息,跟踪审计事件,查出原因。
    通信加密
    DM 提供两种通信方式,即不加密、可选算法的加密通信。选择何种通信方式以服务器
    端为准,通过设置服务器端配置文件中相应选项来指定,客户端以服务器采用的通信方式与
    其进行通信。
    存储加密
    某些信息具有保密要求,实现存储加密的重要性不言而喻。DM 实现了对存储数据的加
    密,另外,还提供了内置的数据加/解密函数,为用户的隐私数据提供更加可靠的保护。
    客体重用
    DM 内置的客体重用机制使数据库管理系统能够清扫被重分配的系统资源,以保证数据
    信息不会因为资源的动态分配而泄露给未授权的用户。
    高可靠、高可用性
    任何一个系统都存在发生各种意外故障的可能性。DM 的高可靠、高可用性可以避免或
    降低系统的意外故障对用户带来的损失,主要包括以下几个方面的功能:
    数据守护
    DM 数据守护(Data Watch)是一种集成化的高可用、高性能数据库解决方案,是数
    据库异地容灾的首选方案。通过部署 DM 数据守护,可以在硬件故障(如磁盘损坏)、自然
    灾害(地震、火灾)等极端情况下,避免数据损坏、丢失,保障数据安全,并且可以快速恢
    复数据库服务,满足用户不间断提供数据库服务的要求。
    DM 数据守护提供多种解决方案,可以配置成实时主备、MPP 主备、或读写分离集群,
    满足用户关于系统可用性、数据安全性、性能等方面的综合需求。
    共享存储集群
    DM 共享存储数据库集群(DM Data Shared Cluster,简称 DMDSC),允许多个数

    据库实例同时访问、操作同一数据库,具有高可用、高性能、负载均衡等特性。DMRAC 支
    持故障自动切换和故障自动重加入,某一个数据库实例故障后,不会导致数据库服务无法提
    供。
    高级复制
    达梦数据复制(DATA REPLICATION)是一个分担系统访问压力、加快异地访问响应
    速度、提高数据可靠性的解决方案。将一个服务器实例上的数据变更复制到另外的服务器实
    例。可以用于解决大、中型应用中出现的因来自不同地域、不同部门、不同类型的数据访问
    请求导致数据库服务器超负荷运行、网络阻塞、远程用户的数据响应迟缓的问题。
    基于 DM 高级复制技术可以实现数据库的异地快速备份、实时快速同步功能;可以根
    据实际应用需要,搭建一对多复制、多对一复制、级联复制、对称复制、循环复制等复杂的
    逻辑复制环境。
    故障恢复措施
    数据库的备份与还原是系统容灾的重要方法。备份意味着把重要的数据复制到安全的存
    储介质上,还原则意味着在必要的时候再把以前备份的数据复制到最初的位置,以保证用户
    可以访问这样的数据。
    DM 数据库管理系统支持的备份方式包括物理备份,逻辑备份和 B 树备份,其中 B 树
    备份是介于物理备份和逻辑备份的一种形态。物理备份分为数据库级的备份和用户表空间级
    的备份;B 树备份分为数据库级的备份和用户表级的备份。为了提高备份恢复的安全性,减
    少备份文件占用磁盘空间的大小,系统支持对备份数据加密和压缩。
    易用性
    为了让用户更加容易掌握达梦数据库,DM 提供了大量功能特性来简化系统的使用、管
    理和维护,具体表现在:
    动态缓冲区
    DM 提供了动态缓冲区管理机制,可以更加有效地利用系统内存资源,提高服务器灵活
    性,减轻系统管理员负担,满足各种应用环境的需求。用户可以在服务器启动时仅分配较少
    的缓冲数据页,或者直接采用缺省的缓冲区配置参数,就可以满足一般的应用需求。当数据
    库服务器发现因为缓冲区不足而产生频繁的缓冲区页面淘汰时,系统会自动扩展缓冲区,减
    少淘汰几率。当系统相对空闲时,DM 又会逐步释放扩展的缓冲区空间,直至最初的规模。
    数据库重演
    数据库重演(Database Replay)是指在数据库系统上捕获所有负载(记录外部客户端对
    服务器的请求),保存到二进制捕获文件,并传送到由原始数据库的备份所恢复出来的重演
    测试系统上。利用捕获文件,重演客户端在系统上所做的所有操作通过重演可再现该段时间
    内真实环境的负载及运行情况,例如可获取系统运行中的出错的操作。通过该功能,可以方
    便地再现用户负载,方便用户定位系统所存在的各种问题。
    同义词
    同义词(Synonym)实际就是让用户能够为数据库的一个模式下的对象提供别名,它可
    以替换模式下的表,视图,序列,函数,存储过程等对象。同义词通过掩盖一个对象真实的
    名字和拥有者来提供了一定的安全性,同时使用同义词可以简化复杂的 SQL 语句。
    动态性能视图

    DM8 中提供了动态性能视图功能(一组以 V$开头的系统表)。通过动态性能视图,数
    据库管理员可以方便地查看当前服务器诸如锁的信息、缓存使用情况、IO 状况等实时性能
    信息,便于找出系统瓶颈,进行系统优化。
    Oracle 兼容性
    目前,大多数应用程序使用的是 Oracle 数据库,用户或多或少地使用了 Oracle 的一些
    特殊功能,而这些特殊功能在其他数据库中都未实现。为了方便应用的移植,DM 实现了很
    多 Oracle 独特的功能和语法,使得多数 Oracle 的应用可以不用修改而直接移植到 DM 上面。
    Oracle 兼容性方面实现的功能包括:ROWNUM 表达式、多列 IN 语法、层次查询、外连接
    语法“(+)”、INSTEAD OF 触发器、%TYPE 以及记录类型等。
    类型别名
    类型别名实际上是为数据类型提供一个更加容易记住和理解的名字,方便用户使用。实
    际上,各大数据库的部分数据类型名称也不相同,通过创建数据类型的别名,可以为应用系
    统的移植和数据的迁移提供便利。
    执行计划
    为了方便用户对 SQL 语句性能进行分析和调整,DM 提供了显示执行计划的功能。
    简便的数据库系统安装和配置
    统一的界面,熟悉的环境
    DM 提供一个基于 Java 的安装程序,利用 Java 的跨平台性,可以在 Windows、Unix、
    Linux、Solaris 等平台上运行,且具有统一界面。这样,无论在什么平台上,它都可以为管
    理员提供一个简洁的安装界面,熟悉、统一的安装环境。
    便捷的安装向导
    DM 的安装程序把软件安装、数据库初始化和配置结合在一起,一气呵成。
    配置灵活
    DM 为常见应用做了缺省优化配置,用户可以一路“确认”下来,完成安装,也可自行
    调整。在安装过程中,安装程序提供一个交互界面来初始化数据库,通过 DM 提供的控制
    台工具,管理员可以方便地根据实际应用配置 DM 数据库的各项参数,从而获得最大的应
    用性能。详尽的提示信息减少了用户在安装过程中可能出现的问题。通过降低安装的复杂性,
    简化配置操作,数据库管理员可提高工作效率,普通技术人员也很容易成为数据库系统管理
    员。
    集成的系统管理工具 Manager
    DM 系统管理工具 Manager 是管理 DM 数据库系统的图形化工具,类似于 Oracle 和 MS
    SQL Server 的 Enterprise Manager。Manager 可以帮助系统管理员更直观、更方便地管理和维
    护 DM 数据库,普通用户也可以通过 Manager 完成对数据库对象的操作。Manager 的管理功
    能完备,能对 DM 数据库进行较为全面的管理,在不借助其他工具的情况下,能满足系统
    管理员和用户的常规要求。
    同时,管理工具 Manager 还集成了安全管理的功能:
    DM 安全管理员可以通过 Manager 进行标记管理,同时它也为 DM 安全管理员提供
    了管理安全管理员以及安全管理员登录的操作界面;
    DM 审计员可以用 Manager 来监视、记录、分析用户对数据库的操作,同时它也为
    DM 审计管理员提供了管理审计员以及审计员登录的操作界面。
    数据迁移工具 DTS

    DM 数据迁移工具 DTS 可跨平台实现数据库之间的数据和结构互导,例如 DM 与 DM
    之间、DM 与 ORACLE、MS SQL Server 之间等,也可复制从 SQL 查询中获得的数据,还
    可实现数据库与文本文件之间的数据或者结构互导。
    为了实现与 ORACLE、DB2、SQL Server 等多种主流数据库管理系统的数据交换,DM
    提供跨平台的数据迁移工具 DTS。它是一个用纯 Java 编写的基于 JDBC/ODBC 的数据迁移
    工具,可跨平台实现数据库之间的数据和结构互导,也可复制从 SQL 查询中获得的数据,
    还可实现数据库与文本文件之间的数据或者结构互导。在迁移的过程中它最大限度地保留了
    源数据的原始信息(包括源数据的类型、精度、默认值、主键和外键约束等),还支持迁移
    过程中的数据类型自动转换,关于转换方面的细节问题可由数据迁移工具自动来为您解决,
    数据库管理员所要做的仅仅是指定需要进行数据迁移的两个数据库的连接参数和所迁移的
    数据。
    DM 良好的数据迁移解决方案为系统移植工作减少了很大一部分工作量,免去系统管理
    员和开发人员的后顾之忧,能够将更多的精力投入到应用程序的移植上面来。
    性能监控工具 Monitor
    DM 性能监控工具 Monitor 是 DM 系统管理员用来监视服务器的活动和性能情况的客户
    端工具。它允许系统管理员在本机或远程监控服务器的运行状况,并根据系统情况对系统参
    数进行调整,以提高系统效率。
    控制台工具 Console
    DM 控制台(Console)是数据库管理员(DBA)管理和维护 DM 数据库的基本工具。
    通过使用 DM 控制台,数据库管理员可以完成修改服务器配置参数,启动、停止数据库服
    务,脱机备份与恢复,以及系统信息查看等任务。
    命令行控制台工具
    为方便批处理、编程使用,大部分功能都提供命令行方式,如交互式工具 disql、初始
    化库工具 dminit、备份恢复工具 DMRMAN、快速数据装载工具 dmfldr、导入导出工具
    dexp/dimp、数据库重演工具 dreplay 等。
    海量数据存储和管理
    DM 的数据存储逻辑上分为 4 个层次:数据库实例、表空间、数据文件、数据块。
    DM 每个数据库实例理论上可包含多达 65535 个表空间,每个表空间可包含 256 个数据
    文件,每个数据文件由若干数据块构成。每个数据文件的大小最大为 32K*4G,因此 DM 最
    大数据存储容量达到 TB 级(实际上远远超过),足以支持大型应用。
    此外,DM 全面支持 64 位计算,极大地扩展了系统支持的数据存储和内存容量,这也
    有利于满足大型应用对海量数据存储和管理的要求。
    全文检索
    现有的数据库系统,绝大多数是以结构化数据为检索的主要目标,因此实现相对简单。
    比如数值检索,可以建立一张排序好的索引表,这样速度可以得到提高。但对于非结构化数
    据,即全文数据,要想实现检索,一般都是采用模糊查询的方式实现的。这种方式不仅速度
    慢,而且容易将汉字切分错,于是引入了全文索引技术。
    全文检索的主要目的,就是实现对大容量的非结构化数据的快速查找。DM 实现了全文
    检索功能,它根据已有词库建立全文索引,然后文本查询完全在索引上进行。词库(包括中、
    英文等多种语言)由单独的软件进行维护和更新。全文索引为在字符串数据中进行复杂的词
    搜索提供了有效支持。全文索引是解决海量数据模糊查询的较好解决办法。
    全文检索支持的检索类型有:
    支持英文单词的检索(单词不区分大小写)
    支持全角英文的检索
    支持中文词语的检索
    支持常见单个汉字的检索
    支持中文长句子的检索
    支持中英文混合的检索
    对存储模块的支持
    DM 系统允许用户使用 DM 提供的 DMSQL 过程语言创建存储过程或存储函数,通常,
    我们将存储过程和存储函数统称为存储模块。存储模块运行在服务器端,在功能上相当于客
    户端的一段 SQL 批处理程序,但是在许多方面有着后者无法比拟的优点,它为用户提供了
    一种高效率的编程手段,成为现代数据库系统的重要特征。
    存储模块在执行时数据对用户是不可见的,提高了数据库的安全性;
    存储模块是一种高效访问数据库的机制,使用存储模块可减少应用对 DM 的调用,
    降低了系统资源浪费,显著提高性能,尤其是在网络上与 DM 通讯的应用更显著。
    对 Web 应用的支持
    DM 提供 ODBC 驱动程序和 OLE DB Provider,支持 ADO、.NET 应用。支持在 ASP 动
    态网页中访问 DM。
    DM 还提供 PHP 接口,支持 PHP 动态网页技术。
    DM 提供符合 JDBC CompliantTM规范的第四类纯 Java 的 JDBC 驱动程序,可以在以下
    情形中通过 JDBC 访问 DM:
    在 Eclipse、JBuilder 等应用开发工具中;
    在 JavaBeans 组件、EJB 组件中;
    在 JSP、Applet、Servlet 等基于 Java 的动态网页中。
    以上特性使得 DM 适应 Web 应用,用户只用浏览器就可以访问 DM 数据库。
    DM 支持 Java 数据对象 JDO(Java Data Objects ),JDO 为对象持久性提供了第一个标
    准化的、完全面向对象的方法。JDO 简化了用 Java 语言进行数据库编程的复杂性,而且对
    原始的 Java 源代码的打乱程度最小。

    展开全文
  • 数据库是一个长期存储在计算机内,有组织的,有共享的,统一化管理数据集合。 它简便而言之就是一个数据存储仓库,为了方便数据存储和管理,它将数据按照特定的规律存储在磁盘上。通过数据库管理系统,可以有效的...

    一:什么是数据库
    数据库是一个长期存储在计算机内,有组织的,有共享的,统一化管理数据集合。
    它简便而言之就是一个数据存储仓库,为了方便数据存储和管理,它将数据按照特定的规律存储在磁盘上。通过数据库管理系统,可以有效的组织和管理存储在数据中的数据。

    二:数据库的现状
    数据库类型:
    1.层次数据库 2.网格状数据库 3.关系型数据库 4.NOSQL(非关系型数据库)

    三:数据库系统
    (1)数据库:用于存储数据的地方。
    (2)数据库管理系统:为了提高数据库系统的处理能力所使用的管理数据库的软件
    (3)数据库应用程序:数据库管理系统的软件补充。
    数据库(database)提供了一个存储空间用来存储数据,可以把数据库看成是以存放数据的容器。一个数据库肯定能包含许多文件,一个数据库系统中包含多个数据库
    数据库管理系统(database management system.dbms):是用户创建,管理和维护数据库时使用的软件,位于用户与操作系统之间,对数据库进行统一的管理,dbms能定义数据存储结构,提供数据的操作机制,维护数据库的安全性,完整性和可靠性。
    数据库应用程序:(database application):虽然已经有数据库管理系统,但是在很多情况下,dbms无法满足对数据管理要求,数据库的应用程序算是dbms的一个软件补充,它能够满足对数据管理的更高要求,还可以使数据库管理过程更加直观,数据库应用呈现负责与dbms进行通信,访问和管理dbms中存储和数据,用户插入,修改,删除DB中的数据

    mysql
    1.什么是mysql
    mysql是一个开源的数据管理系统(DBMS),他是由mysql AB公司开发的。
    mysql是一个跨平台开源关系数据库管理系统,广泛的应用在小型的互联网公司的生产和开发环境中。
    mysql是一个小型的关系型数据库,与其他的大型数据库管理系统如:oracle,db2,sql server相比,mysql的规模更小,功能有限,但是体积小,速度快,成本低,并且它的功能对一些小企业或者复杂一点应用来说已经足够用了,所以mysql就为目前最受欢迎的开源数据库。

    2.mysql的版本
    针对不同的用户mysql分为Community server(社区版),enterprise server(企业版)
    mysql的命名机制由3个数字和1个后缀组成,例如:mysql-5.5.13.
    第一个5.是主版本号,描述了文件格式,所有版本5的发型版都有相同的文件格式。
    第二个5.是发型级别,主版本号和发型别组合在一起便构成了发行序列号
    第三个数字13.是发型序列的版本号

    3.mysql的优势:
    (1)速度:运行速度快;
    (2)价格:开源免费
    (3)容易使用:它的配置和管理非常简单,易于学习。
    (4)可移植性强:能够在众多不同的系统平台运行。比如:widows,linux,ios等等。
    (5)丰富的接口:提供了c c++,Java,Perl,PHP
    (6)支持查询语言:MySQL可以使用sql语法支持ODBC(开放式数据库链接)的应用程序
    (7)安全性和连续性:十分灵活和安全的权限和密码系统,允许基于主机的验证,连接到服务器时,所有密码传输均采用加密的方式,从而保证安全性。并且由于mysql是网络化的,可以在因特网上的任何地方访问,提高了数据的共享效率。

    4.mysql的服务架构:
    client/server–C/S架构(客户端/服务器)

    5.mysql的表:database数据库(最大的数据存储单位)
    table表(数据存储的基本单在关系型数据库中,数据库的表是一系列二维数组的集合,用来存储数据和操作数据的逻辑的逻辑结构。
    它是由纵向的列和横向的行组成,行被称为记录,是组织数据的单位;列被称为字段,每一列表示记录的一个属性,都有相应的描述信息,如数据类型,数据宽度等。
    6.数据类型:
    数据类型决定了数据子计算机中的存储格式,代表不同信息类型,通常的数据类型有:整数数据类型
    浮点数数据类型,二进制数据类型,字符串数据类型,日期/时间数据类型等。

    7.sql语言:
    对数据库进行查询和修改操作的语言。SQL的含义(structured query language)结构化查询语言
    他有3个主要的标准:ANSI(美国国家标准机构)SQL,ANSI对SQL在1992进行了修改,SQL-92或者SQL2。近年又进行了修改,SQL-99。
    SQL语言的4个部分:
    1.数据定义语言data definition language(DDL):drop(删除),create(创建),alter()等语句。
    2.数据的操作语言data manipulation language(DML):insert,update(修改)delete(删除)语句。
    3.数据查询语言data query language(DQL):select(查找)语句。
    4.数据控制语言data control language(DCL):grant,revoke,commit,rollba等语句

    8.MySQL的命令行工具:

    9.语句:
    1.show databases:用于查看当前mysql服务器中包含的库,

    2.show tables:用于查看当前所在的库中包含的表。需要先使用use语句切换到所使用的库use mysql
    mysql数据库文件存放在/usr/local/mysql/data 目录下,每个数据库对应一个子目录,用于存储数据表文件,每个数据表对应为三个文件,扩展名分 别为".frm",".myd",".myi"

    3.create database语句:用于创建一个新的库,需要指定数据库名称作为参数(auth数据库名称) 例:(create database auth)

    4.create table语句:用于在当前库中创建新的表,需要指定数据表名称作为参数(zhy表名称)例:(create database zhy)

    5.drop table语句:用于删除数据库中的表,需要指定’库名 表名’作为参数,若只指定表明参数,则需要通过执行use语句切换到目标库,执行一下操作 可以删除users表 例:(drop table auth.users)

    6.drop database语句:用于删除指定的库,需要指定库名作为参数 例:(drop database auth)

    7.Insert into语句:用于向表中插入新的数据记录 例:(insert into 表名)执行以下操作将会向auth库中的users表插入一条记录

    8.Select语句:用于从指定的表中查找符合条件的数据记录

    9.Describe:用于显示表结构,则需先通过use语句切换到目标库(use mysql切换到mysql数据库)查看mysql库中的user表结构(describe mysql.user) 或者(describe user)这俩语句相同

    10.Update语句:用于修改,更新表中的数据记录。

    11.Delete:用于删除表中指定的数据记录。例如:Delete * from 表名 where 条件表达式

    12.insert into语句:用于向表中插入数据记录,例:insert into 表名(字段1,字段2,…) values(字段1的值,字段2的值,…)

    注意!
    【在执行Update Delete语句时,通常都带where条件,不带条件的Update语句和Delete语句会修改或删除所有记录,是非常危险的行为】

    12.Crant语句:专门设置数据库用户的访问权限,当指定的用户不存在时,Crant语句将会创建新的用户,否则Crant语句用户信息。

    13.show global varlables like’%datadir%’;查看mysql数据存储路径

    14.执行MySQL操作语句
    验证成功以后将会进入提示符“mysql>”的数据操作环境,用户可以输入各种操作语句对数据库进行管理,每条MySQL操作语句以分号“;”表示结束,输入时不区分大小写。

    第二章 数据库的基本操作

    一.mysql的4个默认自带的4个库:
    1.information_schema:保存了关于数据的信息。例如:数据库名,数据库中的表名。
    2.mysql:记录数据库的用户,密码,权限,关键字等,还有mysql自己需要使用的控制和管理信息。
    3.performance_schema:5.5版本之后新增的一个库,用于收集服务器的性能参数。该库中所有的表的一个引擎均为performance_schema。
    4.tsst:测试库,所有的用户在该数据库中都拥有root权限(一般不会存储有用的数据)。

    二.1.创建数据库:create database databasename; databasename是指数据库名称
    2.移动到指定的数据库里:use databasename;
    3.删除数据库:drop database databasename;

    其它用法

    1、使用SHOW语句找出在服务器上当前存在什么数据库:

    mysql> SHOW DATABASES;

    2、创建一个数据库MYSQLDATA

    mysql> CREATE DATABASE MYSQLDATA;

    3、选择你所创建的数据库

    mysql> USE MYSQLDATA; (按回车键出现Database changed 时说明操作成功!)

    4、查看现在的数据库中存在什么表

    mysql> SHOW TABLES;

    5、创建一个数据库表

    mysql> CREATE TABLE MYTABLE (name VARCHAR(20), sex CHAR(1));

    6、显示表的结构:

    mysql> DESCRIBE MYTABLE;

    7、往表中加入记录

    mysql> insert into MYTABLE values (”hyq”,”M”);

    8、用文本方式将数据装入数据库表中(例如D:/mysql.txt)

    mysql> LOAD DATA LOCAL INFILE “D:/mysql.txt” INTO TABLE MYTABLE;

    9、导入.sql文件命令(例如D:/mysql.sql)

    mysql>use database;

    mysql>source d:/mysql.sql;

    三,数据库的存储引擎:
    1.什么是存储引擎:数据库的存储引擎是数据库的底层软件组件,数据库管理系统(Dbms)就是依赖存储引擎来对数据表进行创建,查询,更新和删除操作的。不同的存储引擎提供了不同的存储机制,索引技巧和锁定水平等功能。还可以获得某些特定的功能。现在不同的数据库的管理系统都支持多种不同的存储引擎。mysql的核心就是存储引擎。

    2.MySQL的存储引擎,包括处理事务安全表的引擎和处理非事物安全表的引擎。在MySQL中不需要所有的表都使用同一种引擎,针对具体的需求每一张表都可以选择不同的存储引擎。
    MySQL5.5支持的存储引擎有:InnoDB,MyiSAM,Memory,CVS等。
    查看mysql中所有的存储引擎的命令:show engines\g

    1.myisam存储引擎的特点:
    (1)myisam引擎读取速度快,占用资源少,不支持事务,不支持外键约束,但支持全文索引
    (2)读写相互阻塞,也就是说读数据的时候就不能写数据,写数据的时候就不能读数据;
    (3)myisam引擎只能缓存索引,而不能缓存数据;
    (4)mysql5.5之前的默认引擎。

    使用场景:
    (1)适用于读数据比较多的业务,不适用于读写频繁的业务;
    (2)并发相对较低的业务(纯读或者纯写的高并发也可以),数据修改相对较少的业务;
    (3)硬件资源比较差的机器可以考虑多使用myisam引擎。

    2.InnoDB存储引擎的特点:
    (1)事物类数据表的首选引擎,支持事物安全表,支持行级别锁定和外键,mysql5.5之后的默认引擎;
    (2)具有提交,回滚和崩溃恢复能力的事物安全存储引擎,能处理巨大的数据量,性能及效率高,完全支持外键完整约束条件;
    (3)具有非常高的效的缓存特性,能缓存索引也能缓存数据,对硬件要求高,
    (4)使用InnoDB时,将在mysql数据目录创建一个名为ibdata的10M带大小的自动扩展文件,以及两个名为ib_logfile0和ib_logfile1的5M带大小的日志文件。

    使用场景:
    (1)需要事物支持的业务,高并发的业务;
    (2)数据更新较为频繁的场景,比如:BBS(美国论坛网站),SNS,微博等;
    (3)数据一致性要求较高的业务,比如充值转账,银行卡转账等。k

    memory存储引擎的特点:
    (1)memory存储引擎将表中的数据存储内存中,为查询和引用其他表数据提供快速访问;
    (2)memory存储引擎执行HASH和BETREE索引,不支持BLOB和TEXT列,支持AUTO_INCREMENT列,和对可包括NULL值的列的索引;
    (3)当不在需要memory表的内容时,要释放memory表占用的内存,可以执行delete from或者truncate table,或者删除整个表。

    CSV:将数据保存为CSV格式文件,可以导入到其它数据库中;

    ARCHIVE:归档,将数据zlib进行压缩,被当做仓库使用,一般对他只进行insert和select操作,他适合存储日志。

    mrg_myisam:相当于将多个myisam的合并版,将多个myisam表合并为一个。

    MySQL 修改root密码的四种方法
    1 用set password命令
    首先登陆MySQL
    格式 MySQL > set password for 用户名@localhost=password(‘新密码’)
    例子 MySQL > set password for root@localhost=password(‘123’);
    2 在命令行用 mysqladmin
    格式 mysqladmin -u 用户名 -p 旧密码 password 新密码
    列子mysqladmin -uroot -p123456 password 123

    方法3 用update直接编辑user表
    首先登陆MySQL
    MySQL>use MySQL;
    MySQL> update user set password=password(‘123’)where user=‘root’ and
    host=‘localhost’;
    mysql>flush privileges;
    方法4 :忘记root密码的时候
    vim /etc/my.cnf
    在[mysqld]下面添加一行skip-grant-tables
    然后重启,在登陆MySQL(此时密码为空)使用命令 update mysql.user set password=password(‘密码’)where user=root host=‘localhost’;
    回到配置文件,删除刚刚添加的那行,在重启服务就可以用新密码登陆了。

    第三章:数据表的基本操作

    我们要进行表的操作,我们首选需要进入一个库里面。
    1.创建表的命令格式:
    create table <表名> (
    –>字段1 数据类型 [完整性约束条件]
    –>字段2 数据类型 [完整性约束条件]

    );
    2.删除表:drop table表名;
    3.如何在表中插入数据:insert into表名 [(插入数据的字段)] values(字段一的值,字段二的值,字段n的值);
    4.擦汗寻表数据:select */字段 from 表明;

    完整性约束条件:
    1.什么是完整性约束条件:
    完整性约束条件时用来对字段进行限制,要求用户只能向该字段中写入符合条件的数据,如果不满足条件数据将会不执行该操作。
    2.常用的完整性约束条件:
    primary key 主键 标识该表的主键,可以唯一的标识数据。(特点: 非空,唯一)
    FOREIGN KEY 外键 标识该字段为该表的外键,是与之联系的某表的主键;
    NOT NULL 非空 标识该字段的值不能为空;
    UNIQUE 唯一 标识该字段的值是唯一的;
    AUTO_INCREMENT 标识该字段的值自动增加,一般该字段的数据类型是int;
    DEFAULT 默认值 为该字段设置一个默认值,在不插入值的时候使用默认值。
    给字段添加主键的方法:
    1.单字段主键:
    语法:
    创建表的时候添加主键
    1.字段名 数据类型 PRIMARY KEY,
    2.在定义完所有的字段之后添加主键
    PRIMARY KEY(字段名);
    多字段的联合主键:
    RIMARY KEY(字段1,字段2,字段3…)

    使用修改表的命令也可以添加主键:
    LTER TABLE 数据表名 ADD PRIMARY KEY(字段名)

    使用外键:外键用来在两个表数据之间建立关系,它可以是一系列或多系列
    创建外键的语法:
    在创建表的时候添加在所有字段后面
    [CONSTRAINT<外键名>]FOREIGN KEY(字段名1,字段2…)REFERENCES 父表(主键1,主键2…)

    用修改表的语法来添加一个外键:
    ALTER TABLE 子表名 ADD CONSTRAINT 外键名 FOREIGN KEY(子表外键列)REFERENCES父表名(父表主键列);
    子表外键列的数据类型必须和父表的主键列的数据类型一致,否则无法创建

    删除外键:
    ALTER TABLE 表名 DROP FOREIGN KEY(外键)

    NO NULL 创建表的时候:
    字段 数据类型 NOT NULL

    UNIQUE
    字段 数据类型 UNIQUE

    [CONSTRAINT(约束名称)]UNIQUE(字段名)

    DEFAULT 默认值
    字段名 数据类型 DEFAULT(默认值)

    AUTO_INCREMENT 自增
    字段名 数据类型 AUTO_INCREMENT

    所有的约束条件都是可选的,每一个字段可以设置多个约束条件。

    查看数据表结构语法;desc+表名;
    2.show create table 表明;

    二,修改数据表:
    1.给表改名:
    alter table<旧表名>rename[to] <新表名>;
    使用这条命令还可以将数据表移动到其他库中
    alter table<旧表名> rename to <库名>.<表名>

    2.修改字段的数据类型
    alter table<表名>modify<字段名><新的数据类型>;

    3.修改字段名:
    alter table<表名>change<旧的字段> <新字段> <新数据类型>;

    4.添加字段:
    alter table<表名> add <新字段> <数据类型> [完整性约束条件] [first/after已经存在的字段](first移动到第一)(after移动到其他字段后面)

    5.修改字段的所在位置:
    alter table <表名> modify <新字段名> <数据类型> [完整性约束条件] after <旧字段>;

    6。删除字段的语法:
    alter table<表名>drop <字段名称>

    7.更改表的引擎:
    alter table <表名> engine=引擎名称;

    8.删除主键:
    alter table <表名> drop promary key;

    9.删除外键:
    alter table <表名> drop foreign key <外键名>;

    10.删除外键:
    ALTER TABLE 表名 DROP FOREIGN KEY(外键)

    如果表b的外键关联表a的主键
    ,那么我们无法删除表a,必须删除表b的外键或者是直接删除表b,才可以删除表a;
    NOT NULL 非空
    UNIQUE唯一
    PRIMARY KEY主键
    FOREIGN KEY外键
    t_name老师名字
    t_birthday性别
    t_prof出生年月日
    t_depart职称
    t_id编号

    数据类型;
    (1)数据表由多列字段构成,每个字段指定不同的数据类型,指定数据类型后,也就决定向字段插入数据的内容;
    (2)不同的数据类型也决定了MySQL在存储他们的时候使用方式,以及在使用他们的时候选择什么运算符号进行运算;
    (3)数据类型分为:数值类数据类型,日期/时间数据类型,字符串数据类型。
    数值数据类型: (1)整数 (2)浮点数 (3)定点数;
    日期/时间数据类型:DATE ,TIME,DATETIME,TIMESTAMP等等;
    字符串数据类型:文本字符串,二进制字符串。

    一,数值类数据类型:

    浮点数和定点数:
    (1)他们都是用来表示小数的,浮点数有两种类型:单精度浮点数(FLOAT)和双精度浮点数(DOUBLE),定点数只有DECIMAL
    (2)浮点数和定点数都可以用(M,D)来表示,其中M是精度,表示总共的位数(不算点号),D是标数,表示小数的位数;
    (3)DECIMAL 实际是以字符串的形式存放的,在对精度要求比较高的时候(比如货币,科学数据等使用DECIMAL类型比较好;

    (4)浮点数相对于定点数的优点是在长度一定的情况下,浮点数能够表示更大的数据范围,它的缺点是精度没有定点数高。

    类型名称 日期格式 日期范围 存储需求
    YEAR YYYY 1901 ~ 2155 1字节
    TIME HH:MM:SS -838:59:59 ~ 838:59:59 3字节
    DATE YYYY-MM-DD 1000-01-01 ~ 9999-12-31 3字节
    DATETIME YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 8字节
    TIMESTAMP YYYY-MM-DD HH:MM:SS 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC 4字节

    2、TIME
    (1) TIME 类型的格式为 HH:MM:SS ,HH 表示小时,MM 表示分钟,SS 表示秒
    (2) 格式:以 ‘HHMMSS’ 格式表示的 TIME ,例如 ‘101112’ 被理解为 10:11:12 ,但如果插入不合法的时间,如 ‘109712’ ,则被存储为 00:00:00
    (3) 格式:以 ‘D HH:MM:SS’ 字符串格式表示的 TIME ,其中 D 表示日,可以取 0 ~ 34 之间的值,在插入数据库的时候 D 会被转换成小时,如 ‘2 10:10’ 在数据库中表示为 58:10:10 ,即 2x24+10 = 58

    3、DATE
    (1) DATE 类型的格式为 YYYY-MM-DD ,其中,YYYY 表示年,MM 表示月,DD 表示日
    (2) 格式:‘YYYY-MM-DD’ 或 ‘YYYYMMDD’ ,取值范围为 ‘1000-01-01’ ~ ‘9999-12-31’
    (3) 格式:‘YY-MM-DD’ 或 ‘YYMMDD’ ,这里 YY 表示两位的年值,范围为 ‘00’ ~ ‘99’ ,其中,‘00’ ~ ‘69’ 被转换为 2000 ~ 2069 ,‘70’ ~ ‘99’ 被转换为 1970 ~ 1999

    (4) 格式:YY-MM-DD 或 YYMMDD ,数字格式表示的日期,其中 YY 范围为 00 ~ 99 ,其中,00 ~ 69 被转换为 2000 ~ 2069 ,70 ~ 99 被转换为 1970 ~ 1999

    查询:
    查询的基础语法:
    SELECT{*|字段} [FROM表1,表2,… ] [WHERE条件判断]
    [GROUP BY 字段] [having expr]
    [order by 字段] [limit…(偏移量,行数)] ORDER BY 字段

    我们知道从MySQL表中使用SQL SELECT 语句来读取数据。
    1.如需有条件的从表中选取数据,可以将WHERE子句添加到SELECT语句中。
    2.查询语句中你可以使用一个或多个表,表之间用逗号隔开,并使用WHERE语句来设定查询条件;
    3.你可以用WHERE语句来指定任何条件
    4.你可以用AND或者OR指定多个条件;
    5.WHRE子句也可以用在DELECT或者UPDATE命令里面。
    WHERE中常用到的:
    (1)=,<>, !=, <, >, <=, >=,
    (2)BETWEEN AND 介于两者之间用来限制一个范围
    (3)LIKE 通配符查询(%匹配任意个数字符,_匹配任意单个字符)
    (4)REGEXP正则表达式查询(^表示以什么开头,$表示以什么结尾,[…]表示匹配方括号内的任意字符串 | 表示匹配管道符前后字符串)
    (5)IN判断是否在IN列表之中;
    (6)AND满足AND前后所有条件,OR满足OR前后任意添加;
    (7)在WHERE子句中我们binary这个参数可以区分大小写,默认不区分;
    (8)ORDER BY 字段 ASC:(升序排列)默认就是升序排列;
    (9)ORDER BY 字段 DESC(降序排列);
    可以同时给多个字段进行排序,排序依然依照第一个字段进行排序,在第一个字段排序过后的基础上,在给其他进行排序,后面的排序不影响第一个字段的顺序;

    分组查询:GROUP BY
    GROUP BY 是对select查询出来结果按照某个字段或者表达式进行分组,获取一组组的集合,然后从每组中取出一个指定的字段或者表达式的值。
    having:用于where和group by 查询出来的分组进行过滤,查出满足条件的分组结果,他是一个过滤声明,是在查询返回结果集以后对查询结果进行过滤操作。
    [GROUP BY 字段] [HAVING 条件表达式]
    分组经常和聚合函数一起使用,MAX(), MIN(), COUNT(), AVG(), SUM()
    SUM() 求和 MAX() 求最大值 MIN() 求最小值 AVG() 求平均数
    COUNT() 表示统计数量 (行数)可以用*表示所有记录的行数,字段来显示特定字段的行数;
    GROUP_CONCAT(字段)将分组过后的数据显示完整。

    LIMIT限制查询结果数量:
    LIMIT[位置偏移量], 行数 默认偏移量从0开始,行数限制了显示结果输出多少行;列:从3行到7行,就是2,5
    列:select * from zhy LIMIT 2,5
    连接查询:UNION [all | distinct] 用来连接两个查询语句,将两个查询的结果集,合并为一个结果集;
    结果集:不加参数all的时候默认去掉重复的结果,相同的值只显示一次,加上参数all,显示所有查询内容,不会去掉重复的值。

    联合查询:
    主要进行多表查询的时候使用。
    INNER JOIN 内连接 连接两个表,输出符合条件的数据;
    语法:表1 [INNER] JOIN 表2 ON 限定条件
    如果连接的是同一个表,叫做自连接。
    LEFT 表1 [OUTER] JOIN 表2 ON 限定条件 “左连接”它会显示左表)表1)的全部内容,和右表(表2) 限定条件的内容;

    RIGHT 表1 [OUTER] JOIN 表2 ON 限定条件 “右连接” 它显示右表
    的全部内容和左表的限定条件的内容;

    子查询:指一个查询语句嵌套在另一个查询语句的内部,,子查询在版本4.1版本开始上线。
    子查询在执行查询的过程中会出现一个零时表,查询完成后会自动消失。
    ALL 需要符合所有条件才能输出;
    ANY 只需要符合其中一个条件就可以输出
    EXITS 会将子查询中的所有数据进行判断是否存在,如果存在,外层查询语句进行查询,如果不存在,则停止查询,返回NULL。
    NOT EXITS 对子查询的数据进行判断是否不存在,如果不存在,执行外部查询,存在则返回NULL

    索引:
     索引用于快速找出在某个列中有一特定值的行,不使用索引,MySQL必须从第一条记录开始读完整个表,指导找出相关的行,表越大,查询数据所花费的时间就越多,如果表中查询的列有一个索引,MySQL能够快速到达一个位置去搜索数据文件,而不必查看所有数据,那么将会节省很大一部分时间。
     其中MySQL中的索引的存储类型有两种:BTREE,HASH。
    在MySQL中最常用的存储引擎就是InnoDB和MyISAM这两个存储引擎主要支出的索引的存储方就是BTREE,MEMORY引擎支持
    HASH
    HASH 主要以KEY-value的方式进行存储数据,多个key可以指向一个value,但是同一个key不可以指向多个值。

    索引的分类:
    1.唯一索引和普通索引
    2.单列索引和组合索引
    3.全文索引fulltext
    4.空间索引spatial
    单列索引指给单行的数据添加索引,组合索引指,将多个字段添加为一个索引;
    唯一索引用来限制我们的数据的唯一性UNIQUE INDEXT,可以包含NULL,PRIMARY KEY
    是一个特殊的唯一索引,唯一,非空;
    全文索引:可以用于全文搜索,只有MyISAM存储引擎支持,并且只能为CHAR,VARCHAR,TEXT列添加;
    空间索引:只有MYISAM引擎支持,添加空间索引的字段必须非空;
    空间类型支持的数据类型:GEOMETRY,POINT,LINESTRING,POLYGON

    组合索引默认的索引名是我们定义的最左侧的第一个字段的名称,组合索引遵循最左侧原则,就是说

    索引的添加方式:
    1.在创建表时添加:
     CREATE TABLE 表名 (字段名 数据类型) (UNIQUE 唯一索引 | fulltext 全文索引 | spatial 空间索引)[INDEX|KEY][索引名(len)]
    2.修改表时添加索引:
     ALTER TABLE 表名 ADD UNIQUE |FULLTEXT|SPATLAL [INDEX|KEY] [索引名] (索引字段)

    3.CREATE UNIQUE | FULLTEXT | SPATIAL [INDEX|KEY] [索引名]
    ON 表名 [索引字段] ;

    查看创建的索引:
    show create table 表名\G
    删除索引:
    ALTER TABLE DROP INDEX 索引名;
    DROP INDEX 索引名 ON 表名;

    创建索引注意:
    (1)创建索引并非越多越好;
    (2)数据量小的表没有必要创建索引
    (3)避免对经常更新的数据创建索引
    (4)在条件表达式中经常使用的字段可以创建索引
    (5)当唯一性是某种数据本身的特征时,我们创建唯一索引
    (6)在频繁进行排序或者分组的列上创建索引,如果排序的列有多个,可以创建全文索引

    索引作用:
    1.加快查询速度
    2.创建唯一索引来保证表中数据的唯一性
    3.实现数据的完整性,加速表和表之间的连接
    4.介绍分组和排序时间

    EXPLAIN + 查询语句 用来测试我们的索引有没有生效或者有没有在工作;

    EXPLAIN列的解释
    table 显示这一行的数据是关于哪张表的
    type 这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL
    possible_keys 显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句
    key 实际使用的索引。如果为NULL,则没有使用索引。
    key_len 使用的索引的长度。在不损失精确性的情况下,长度越短越好
    ref 显示索引的哪一列被使用了,如果可能的话,是一个常数
    rows MYSQL认为必须检查的用来返回请求数据的行数
    Extra 关于MYSQL如何解析查询的额外信息。

    视图优点

    • 简单
    – 使用视图的用户完全不需要关心视图中的数据是通过什么查询得到的。
    – 视图中的数据对用户来说已经是过滤好的符合条件的结果集。
    • 安全
    – 用户只能看到视图中的数据。
    • 数据独立
    – 一旦视图的结构确定了,可以屏蔽表结构变化对用户的影响。

    视图:视图是一张虚拟表;
    他和我们真实的表的区别:视图它里面的数据是通过查询语句从一张或者多张真实的表里面获取到的;
    我们可以通过insert,update, delete来操作视图(和操作表是一样的)。当通过视图修改数据时,对应的原表数据也会被修改,同样,我们修改表数据时,也会自动反映到视图中。

    视图他会真实的保存到我们的磁盘里,随时都能够查询里面的数据;
    视图对应的真实表,我们叫做基表;

    创建视图:
    CREATE [algorithm=undefind|merge|temptable] VIEW 视图名 [视图的字段名] AS SELEST [*|字段]
    FROM 表名|视图名 WHERE…
    例:create view zhy as select * from;

    algorithm 用来定义视图的算法;
    undefined 未定义 默认使用merge
    merge 替换;
    temptable 零时表;

    with check option 默认cascaded
    with cascaded check option 更新视图的时候,满足视图以及相关的基表或视图的限制条件;
    with local check option 更新视图的时候,只需要满足本身的条件即可;

    查看视图结构:DESC 视图名称; SHOW FILEDS FROM 视图名称;

    查看视图的创建详情:SHOW CREATE VIEW 视图名称;

    查看视图的基本信息:
    SHOW TABLE STATUS LIKE ‘视图名’\G
    在MySQL中,information_schema数据库下的views表中存储了所有视图的定义,通过对views表的查询,可以查看数据库中所有视图的详细信息;

    修改视图:
    CREATE OR REPLACE VIEW 视图名 AS SELECT… ‘用来修改视图’
    ALTER VIEW 视图名 AS SELECT…

    更新视图内容:update
    UPDATE 视图名 set 字段名=‘值’ WHERE …

    试图存在以下情况时,更新操作无法执行:
    1.视图中不包含基表中被定义为非空的列;
    2.在定义视图的select语句的字段列表中使用了数学表达式或者聚合函数,不接受更新操作;
    3.select中,使用了union、group by、having无法接受更新。

    删除视图:
    DROP VIEW [IF EXISTS] 视图名1,视图名2,…

    加上IF EXISTS 可以使假如没有要删除的这个视图存在,也不会报错,但是会返回1条warning;

    视图和真实表的区别;
    (1)视图是已经编译好的SQL语句,是基于SQL语句的结果的可视化表,而表不是;
    (2)视图没有实际的记录,而表有;
    (3)表是内容,试图可以看成是窗口;
    (4)表和视图虽然都占用物理空间,但是视图只是逻辑概念存在,而表可以及时对数据进行修改,但是视图只能用创建语言来修改;
    (5)视图是查看数据表的一种方法,可以查询数据表中的某些字段构成的数据,只是一些SQL语句的集合,从安全角度来说,视图可以防止用户接触数据表,因而不知道表结构;
    (6)表属于全局模式的表,是实表,而视图属于局部模式的表,是虚表;
    (7)视图的建立和删除只影响视图本身,而不影响对应的基本表。

    视图和基本表的联系:
     视图是在基本表之上建立的表,他的结构和内容都来自基本表,它依赖基本表存在而存在。
    一个视图可以对应一个基本表,也可以对应多个基本表,视图是基本表的抽象和逻辑意义上建立的关系。

    事务:
    什么叫事务:多条SQL语句,要么全部成功,要么全部失败,MySQL的事务是在存储引擎层实现
    事务主要用于处理操作量大,复杂度高的数据,比如说,在人员管理系统中,你要删除一个人员,你既要删除人员的基本资料,也要删除该人员的相关信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

    事务的四大特性:ACID
    A.原子性(atomicity):一个事务必须视为完整不可分割的单位,其中的操作要么都做,要么都不做;如果事务中的一个SQL语句执行失败,则已执行的语句必须回滚,数据库退回到事务开始前的状态。
    C:一致性(consistency):是指事物执行结束后,数据库的完整性约束没有被破坏,事物执行的前后都是合法的数据状态,数据库的完整性约束包括不限于:实体完整性(如字段的类型,大小,长度要符合要求),外键约束,用户自定义完整性(如转账前后,两个账户余额的和应该不变)。事物支持的操作主要有:INSERT,UPDATE,DELETE等;
    D:持久性(durability):一旦事物提交,所有修改的数据将永久保存到数据库中,即使系统崩溃也不会改变或丢失;
    I:隔离性:与原子性,持久性侧重于研究事物本身不同,隔离性研究的是不同事物之间的相互影响,隔离性是指,事物内部的操作与其他事物是隔离的,并发执行的各个事物之间不能相互干扰,严格的隔离性,对应了事物隔离级别中的serializable(可串行化),但实际应用中出于性能方面的考虑很少会使用可串行化。

    事物操作命令:
    开启事务:begin,start transaction
    事务提交:commit
    事务回滚:rollback

    我们用begin或者start transaction 开启的事务叫做显式事务。

    查看自动提交模式是否开启:SHOW VARIABLES LIKE’AUTOCOMMIT‘
    关闭自动提交模式:SET AUTOCOMMIT=0
    开启自动提交模式:SET AUTOCOMMIT=1

    事务的4种隔离级别:
    1.read uncommitted(未提交读);
    2.read committed(已提交读);
    3.repreatable read(可重复读);
    4.serealizable(可串行化);
    这4种隔离级别是由低到高的,隔离级别越低,并发能力越强,性能越好,但是安全性越差;
    隔离级别也高,并发越差,但是安全性好;

    1.未提交读:事务中修改没有提交对其他事务也是可见的,俗称脏读;
    2.以提交读:许多数据库默认为此级别呢(MySQL不是)。已提交读一个事务只有在提交了之后,另一个事务才对他可见;

    以提交读可以解决脏读的问题,但是会产生不可重复读的问题;

    3.可重复读:能够解决脏读和不可重复读的问题;

    4.可串行读:是最高隔离级别,强制事务串行执行,执行串行也就解决问题了,这个级别只有在对数据一致要求非常严格并且没有并发的情况下使用。
    当我们在事务a里面查询id<10的时候,我们在事务b里执行insert语句被阻塞执行了,原因是事务a执行了查询stud同时满足id<10,以被锁定,如果查询表stud同时满足id<3,则新增的语句执行成功

    触发器(trigger):是一个特殊的存储过程,都是嵌入到MySQL的一段程序,触发器是由事件来触发某个操作,由于MySQL只支持行级别的触发器功能,所以这些事件只能是SQL语言DML语句,也就是inster、delete、update这三种,如果定义了触发程序,当数据库执行这些语句的时候就会激发触发器执行相应的操作,触发器可以查询其他的表,而且可以包含复杂的SQL语句,不需要手动启动,只要一个预定义事件发生时,就会被MySQL自动调用。

    简单来理解:触发器就是你执行一条DML SQL语句,这条SQL执行会自动触发执行其他的SQL语句。

    sql ->触发 ->sqln, 一条触发一个或多个sql。

    触发器的4个要素:
    (1)监视点(table)
    (2)监视事件(insert、update、delete)
    (3)触发时机(before/after)
    (4)触发事件(sql语句)

    NEW和OLD详解:
    MySQL中定义了new和old,用来表示触发器的所在表中,触发了触发器的那一行数据,来引用触发器中发生变化的记录内容,具体的:
    (1)在insert型触发器中,NEW用来表示将要(before)或已经(after)插入或修改后的新数据,old表示没有插入或修改之前的数据;
    (2)在uptate型触发器中,new表示将要(before)或已经(after)修改后的新数据,old表示没有修改之前的数据;
    (3)在delete型触发器中,old表示已经被删除或将要被删除的数据;
    使用方法:NEW.字段名 OLD.字段名

    创建语法:
    CREATE TRIGGER 触发器名 before(之前)或after(之后) 触发事件(insert、delete、update) ON 表名 for each row begin 要执行的sql语句 end

    DELIMITER // 这个命令是将我们的sql语句结束符从’;‘改为’//’

    触发单条sql语句:
    mysql> CREATE TABLE goods(num INT);
    Query OK, 0 rows affected (0.01 sec)

    mysql> CREATE TABLE sale(snum INT);
    Query OK, 0 rows affected (0.06 sec)

    mysql> INSERT INTO goods VALUES(100);
    Query OK, 1 row affected (0.01 sec)

    mysql> INSERT INTO sale VALUES(0);
    Query OK, 1 row affected (0.01 sec)

    mysql> DELIMITER //
    mysql> CREATE TRIGGER gs1 AFTER UPDATE ON goods FOR EACH ROW
    BEGIN UPDATE sale SET snum=OLD.num-NEW.num; END//
    Query OK, 0 rows affected (0.07 sec)

    mysql> DELIMITER ;
    mysql> UPDATE goods SET num=num-20;
    Query OK, 1 row affected (0.01 sec)
    Rows matched: 1 Changed: 1 Warnings: 0

    mysql> SELECT * FROM goods;
    ±-----+
    | num |
    ±-----+
    | 80 |
    ±-----+
    1 row in set (0.00 sec)

    mysql> SELECT * FROM sale;
    ±-----+
    | snum |
    ±-----+
    | 20 |
    ±-----+
    1 row in set (0.00 sec)

    触发多条sql语句:DELIMITER mysql>CREATETRIGGERtestrefBEFOREINSERTONtest1FOREACHROWBEGININSERTINTOtest2SETa2=NEW.a1;DELETEFROMtest3WHEREa3=NEW.a1;UPDATEtest4SETa4=a4+1WHEREa4=NEW.a1;END mysql> CREATE TRIGGER testref BEFORE INSERT ON test1 FOR EACH ROW BEGIN INSERT INTO test2 SET a2=NEW.a1; DELETE FROM test3 WHERE a3=NEW.a1; UPDATE test4 SET a4=a4+1 WHERE a4=NEW.a1; END
    Query OK, 0 rows affected (0.01 sec)

    查看触发器:
    show triggers;或者show triggers\G
    由于触发器的信息统一存储在information_schema.triggers 这个表里,所以我们查看这个表就能看到所有的触发器信息了;
    SELECT * from information_schema.triggers WHERE TRIGGER_NAME=‘tsetref’\G

    删除触发器:DROP TRIGGERS 触发器名:

    MySQL用户与权限:
    1.是否允许用户连接MySQL的server端;usre host password
    2.用户是否拥有对于MySQL库表的操作权限;privileges

    这些权限都记录在mysql.user这个表里

    1.用户列:
    user表里用户列包含Host、User、password,分别表示主机名、用户名、密码。其中user和host为user表里的联合主键。当用户与服务器之间建立连接时,输入的账户信息中的用户名称,主机名,和密码必须匹配user表里对应的字段值,才能够建立连接,我们修改用户实际上就是修改user表里password列对应的值;

    2.权限列:
    权限列的字段决定了用户的权限,描述了在全局范围内允许用户对 数据进行的操作,包括
    查询权限,修改权限等普通权限,还包括了关闭服务器,超级权限和加载用户等高级权限,普通的权限用来操作数据库,高级权限用来管理数据库;user表中对应的权限是针对所有用户数据库的。
    这些字段值的类型为ENUM,可以取的值只有Y和N,Y表示该用户没有对应的权限,修改权限,可以使用GRANT语句或者UPDATE语句更改user表的这些字段对应的值,来修改对应的权限。

    3.安全列 :
    安全列只有6个字段,其中两个是SSL相关的,2个是x509相关的,另外2个事授权插件相关的。SSI用于加密,x509标准可用于标识用户,Plugin字段标识可以用于验证用户身份的插件,如果该字段为空,服务器使用内建授权验证机制验证用户 身份。可以通过SHOW VARIABLES LIKE 'have_openssl’语句来查询服务器是否支持SSL功能;

    4.资源控制列 :
    资源控制列的字段用来限制用户使用的资源,包含4个字段,分别为:
    (1)Max_questions用户每小时运行执行的查询操作次数;
    (2)Nax_updates用户每小时允许执行更新操作的次数;
    (3)Max_connections用户每小时允许执行的连接操作次数;
    (4)Max_user_connections用户允许同时建立的连接次数;

    db表和host表
    这两个表是MySQL数据中非常重要的权限表,db表中存储了用户对某个数据库的操作权限,决定用户能从哪个主机存取哪个数据库,host表中存储某个主机对数据库的操作权限,配合db权限表对给主机上数据库级操作权限做更细致的控制,这个权限表不守GRANT和REVOKE语句的影响,db表比较常用,host表一般很少使用,db表和host表结构相似,字段大致可以分为两类:用户列和权限列。

    新建普通用户:
    1.使用CREATE USER语句来创建新用户:
    CREATE USER user@host [IDENTIFIED BY PASSWORD’password’]
    IDENTIFIED BY 表示用来设置用户密码;[password]:表示使用哈希值设置密码;‘password’:用于登录的明文密码;

    2.使用GRANT语句创建用户:
    GRANT’privileges’ ON db.table TO user@host [IDENTIFIED BY’password’] [with grant option]

    FLUSH PRIVILEGES:这个命令
    privileges 表示赋予用户的权限类型;db.table:表示用户的权限锁作用的数据库中的表;
    with grant option 可选项,表示对新建立的用户赋予grant权限;

    3.直接操作mysql.user:
    mysql> INSERT INTO mysql.user(Host,User,Password) VALUES(‘localhost’,‘wangwu’,‘123.com’);
    Query OK, 1 row affected, 3 warnings (0.00 sec)

    mysql> SHOW warnings;
    ±--------±-----±--------------------------------------------------+
    | Level | Code | Message |
    ±--------±-----±--------------------------------------------------+
    | Warning | 1364 | Field ‘ssl_cipher’ doesn’t have a default value |
    | Warning | 1364 | Field ‘x509_issuer’ doesn’t have a default value |
    | Warning | 1364 | Field ‘x509_subject’ doesn’t have a default value |
    ±--------±-----±--------------------------------------------------+
    3 rows in set (0.00 sec)

    mysql> SELECT * FROM user WHERE user=‘wangwu’\G
    *************************** 1. row ***************************
    Host: localhost
    User: wangwu
    Password: 123.com
    Select_priv: N
    Insert_priv: N
    Update_priv: N
    Delete_priv: N
    Create_priv: N

    通过上面三种方法创建的新用户还不能直接登录到MySQL,我们需要刷新权限才可以登录:FLUSH PRIVLEGES;

    INSERT 这种方法创建用户,我们最好把密码提前进行加密,然后把加密过的密码插入到user表里,
    mysql> SELECT password(‘123.com’);
    ±------------------------------------------+
    | password(‘123.com’) |
    ±------------------------------------------+
    | *AC241830FFDDC8943AB31CBD47D758E79F7953EA |
    ±------------------------------------------+
    1 row in set (0.02 sec)

    删除普通用户:
    1.使用DROP USER user@host;删除;
    mysql> DROP USER ‘zhangsan’@‘localhost’;
    Query OK, 0 rows affected (0.00 sec)
    2.使用DELETE语句删除用户:
    DELETE FROM mysql.user WHERE host=‘localhost’ and user=‘zhangsan’;

    root用户修改自己的密码:
    1.使用mysqladmin命令来修改密码:
    mysqladmin -u root -h localhost -p password “newpassword”
    Enter password: //这里输入root的旧密码

    2.修改mysql库的user表:
    mysql> UPDATE mysql.user SET password=password(‘123.com’) WHERE user=‘root’ and host=‘localhost’;
    Query OK, 1 row affected (0.00 sec)
    Rows matched: 1 Changed: 1 Warnings: 0

    mysql> flush privileges;(刷新权限)
    Query OK, 0 rows affected (0.00 sec)

    3.使用SET语句来修改root用户的密码(修改当前登录用户的密码):
    SET PASSWORD=PASSWORD(‘newpassword’);

    4.那当然你set语句还可以修改其他普通用户的密码:
    SET PASSWORD FOR user@host=password(‘newpassword’);
    mysql> SET PASSWORD FOR ‘zhangsan’@‘localhost’=password(‘123.com’);
    Query OK, 0 rows affected (0.00 sec)

    修改普通用户的密码我们还可以用grant授权的方式:
    mysql>grant usage on . to ‘zhangsan’@'localhost’identified by ‘321.com’;
    Query OK rows affected (0.00 sec)

    mysql>flush privileges;

    root密码忘记了怎么办?
    使用–skip-grant-tables选项启动mysql然后在设置密码:
    [root@localhost ~]# /etc/init.d/mysqld restart --skip-grant-tables
    Shutting down MySQL. SUCCESS!
    Starting MySQL… SUCCESS!
    [root@localhost ~]# mysql -uroot -p
    Enter password: //这里直接回车进入mysql
    mysql> UPDATE mysql.user SET password=password(‘1234.com’) WHERE user=‘root’ and host=‘localhost’;
    Query OK, 0 rows affected (0.00 sec)
    Rows matched: 1 Changed: 0 Warnings: 0

    mysql> flush privileges;
    Query OK, 0 rows affected (0.00 sec)

    [root@localhost ~]# systemctl restart mysqld

    权限管理:
    权限管理主要是对登录到mysql的用户进行权限验证,所有用户的权限都储存在mysql的权限表里,不合理的权限规划给mysql服务器带来安全隐患。mysql权限系统的主要功能是证实连接到一台给主机的用户,并赋予该用户在数据库中SELECT /INSERT/UPDATE和DELETE等权限,账户权限信息被存储在MySQL数据库 的user、db、host、tables_priv、columns_priv等权限表里。在MySQL启动时,服务器将这些库表中的权限信息读入内存中。

    1.CREATE和DROP权限,可以创建新数据和表,或删除已有的数据库和表,如果将mysql数据库中的DROP权限授予某个用户,这个用户就可以删除它有访问权限的数据库和表。
    2.SELECT、INSERT、UPDATE和DELETE权限允许在一个数据库现有的表里实施操作。
    3.SELECT权限只有在他们真正从一个表中检索行时才被用到;
    4.INDEX权限允许创建或删除索引,INDEX使用已有表,如果具有表的CREATE权限,可以在CREATE TABLE语句中包括索引定义。
    5.ALTER 权限,可以使用ALTER TABLE来更改表的结构和重新命名表。
    6.GRANET权限,允许授权给其他用户,可用于数据库、表和保存的程序。
    7.file权限给与用户使用LOAD DATA INFILE和SELECT…INTO OUTFILE语句读或者写服务器上的文件,任何被授予file权限的用户都能读或写mysql服务器上的任何文件。(说明用户可以读任何数据目录下的文件,因为服务器可以访问这些文件)。file权限允许用户在MySQL服务器具有写权限目录下创建文件,但不能覆盖已有文件。

    授权:
    授权就是为某个用户授予授权,合理的授权可以保证数据库的安全,MySQL中可以使用grant语句为用户授权。
    1.全局层级
    全局权限适用于一个给定服务中的所有数据库。这些权限存储在MySQL表中,CRANT ALL  ON *.*和REVOKE ALL ON *.*指收于和撤销全局权限。
    2.数据库层级
    数据库权限适用于一个给定数据库中的所有目标,这些权限存储在mysql.db和mysql.host表中。
    GRANT ALL ON db_name 和REVOKE ALL db_name; 只授予和撤销数据库权限。

    3.表层级:
    表权限适用于一个给定表中的所有列,这些权限存储在mysql.tables_priv表中。CRANT ALL ON table_name;和REVOKE ALL ON table_name;只针对表授予或撤销权限。

    4.列层级:
    列权限适用于一个给定表中的某单一的列,这些权限保存在mysql.column_priv表中。当使用REVOKE时,必须指定与被授权相同的列。

    在mysq中,必须拥有GRANT权限的用户才可以执行grant语句,要使用grant或revoke,必须有grant option权限。

    GRANT语法:
    CRANT priv_type1, priv_type2, priv_type3,…ON dbname.tablename,dbname.tablename…TO user@host;

    REVOKE(收回权限)语法:
    REVOKE priv_type1, priv_type2, priv_type3,…ON dbname.tablename,dbname.tablename…TO user@host;

    查看权限:
    SHOW GRANTS语句可以显示指定用户的权限信息;
    SHOW GRANTS FOR ‘user’@‘host’;

    用SELECT语句查看user表中的各个权限字段以确定用户的权限信息
    SELECT privileges_llist FRO mysql.user WHERE user

    mysql的日志:
    mysql日志记录了mysql数据库日常操作和错误信息。mysql有不同类型的日志文件(各自存储了不同类型的日志),从日志当中可以查询到mysql数据库的运行情况、用户的操作、错误的信息等。

    MySQL日志分为4大类:
    1.错误日志:记录mysql服务的启动,运行或停止mysql服务时出现问题;
    2.一般查询日志:记录建立连接客户端的执行的sql语句(耗费时间在<=long_query_tme设定的时间内);
    3.慢查询日志:记录所有执行的sql语句的时间超过long_query_time的所有查询;
    4.二进制日志:记录所有更改数据的语句,可以用于数据复制和恢复。

    默认情况下,所有日志创建于mysql数据目录中,通过刷新日志,可以强制mysql关闭和重新打开日志文件,flush logs刷新日志或执行mysqladmin flush-logs 如果正在使用mysql复制功能,在复制服务器上可以维护更多日志文件,这种日志我们称为接替日志。启动日志文件可能会降低mysql数据库的性能(官方表示,降低的性能不大于1%),
    二进制日志:
    主要记录mysql数据的变化,二进制日志以一种有效的格式并且是事务安全的方式包含更新日志中可用的信息。二进制日志包含了所有更新了的数据。二级制日志还包含关于每个更新数据的语句的执行时间,它不包含没有修改任何数据的语句(select、show等)。
    使用二进制日志的主要目的是最大可能的恢复数据。

    启动二进制日志,默认情况下二进制日志关闭的(开启日志会降低服务器性能),编辑匹配文件my.cnf来开启二进制日志:

    格式:
    [mysqld]
    log-bin=/date/logs/mysql-bin
    expire_logs_days=10
    Max_binlog_size=100M

    log-bin [=path/[filename]] //二进制日志[路径]指定日志文件的名字
    Expire_logs_days=10
    Max_binlog_size=100M
    默认为1GB
    binlog_format=mixed

    重启mysql,重启mysql也会产生二进制日志,flush logs 也会出现二进制日志。

    二进制日志默认和mysql数据目录下(/var/mysql),我们也可以自定义。

    查看二进制日志是否开启:SHOW VARIABLES LIKE’log_%’\G

    【查看二进制日志】
    MySQL二进制日志存储了所有变更信息,mysql二进制日志经常使用。。当mysql创建二进制日志文件时,首先创建一个以‘filename’(默认bin-log)为名称,以‘index’为后缀的索引文件(这个文件是用来记录二进制日志的文件名的);在创建一个以‘filename’为名称,以‘000001’为后缀日志文件。当mysql服务重启一次,以‘000001’为后缀的文件会增加一个,并且后缀加1递增,如果日志长度超过max_binlog_size的上限,也会创建一个新的日志。

    show binary/master logs;可以查看当前的二进制日志文件个数及其文件名。
    想要查看二进制内容,需要通过mysqlbinlog工具。

    【删除二进制日志】
    mysql的二进制文件可以匹配自动删除,也可以手动删除:
    1.RESET MASTER;用来删除所有二进制日志文件
    2.PPURGE MASTER/BINARY LOGS TO ‘二进制日志文件名’;用来删除单个日志文件。
    mysql> SHOW BINARY LOGS;
    ±-----------------±----------+
    | Log_name | File_size |
    ±-----------------±----------+
    | mysql-bin.000001 | 27130 |
    | mysql-bin.000002 | 1031892 |
    | mysql-bin.000003 | 1857 |
    | mysql-bin.000004 | 478 |
    | mysql-bin.000005 | 1398 |
    | mysql-bin.000006 | 479 |
    | mysql-bin.000007 | 126 |
    | mysql-bin.000008 | 462 |
    | mysql-bin.000009 | 126 |
    | mysql-bin.000010 | 516 |
    ±-----------------±----------+
    10 rows in set (0.00 sec)

    mysql> PURGE MASTER LOGS TO ‘mysql-bin.000002’;
    Query OK, 0 rows affected (0.00 sec)

    mysql> SHOW BINARY LOGS;
    ±-----------------±----------+
    | Log_name | File_size |
    ±-----------------±----------+
    | mysql-bin.000002 | 1031892 |
    | mysql-bin.000003 | 1857 |
    | mysql-bin.000004 | 478 |
    | mysql-bin.000005 | 1398 |
    | mysql-bin.000006 | 479 |
    | mysql-bin.000007 | 126 |
    | mysql-bin.000008 | 462 |
    | mysql-bin.000009 | 126 |
    | mysql-bin.000010 | 516 |
    ±-----------------±----------+
    9 rows in set (0.00 sec)

    3.PERGE BINARY/MASTER LOGS BEFORE ‘date(日期名字)’

    mysql> PURGE MASTER LOGS BEFORE ‘20200227’;
    Query OK, 0 rows affected (0.01 sec)

    mysql> SHOW BINARY LOGS;
    ±-----------------±----------+
    | Log_name | File_size |
    ±-----------------±----------+
    | mysql-bin.000010 | 516 |
    ±-----------------±----------+
    1 row in set (0.00 sec)

    【还原】
    如果mysql服务器启用了二进制日志,使用二进制日志还原数据库,使用最后一次备份还原,或指定一个时间恢复数据。
    MYSQLBINLOG [option] 日志文件名 mysql -u usre -p ‘password’

    [option]里面的选项–start-date 开始时间 --stop-positon=结束的位置;
    [root@localhost bin]# ./mysqlbinlog --start-datetime=‘2020-02-26 23:23:56’ /usr/local/mysql/data/mysql-bin.000010 -uroot -p1234.com

    【暂时停止二进制日志的功能】
    如果mysql的配置文件已经启动了二进制日志,mysql会一直记录二进制日志,修改配置文件,可以停止二进制日志,但是需要从起mysql。mysql提供了暂时停止二进制日志的功能,通过SET SQL_LOG_BIN语句可以是mysql暂时停止二进制
    mysql>SET SQL_LOG_BIN=0; 暂停二进制

    错误日志:
    错误日志文件包含了当mysql启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。

    设置错误日志:
    在默认的情况下错误日志是开启的,它默认被记录到数据目录下/var/mysql/data/。如果,没有在配置文件中指定文件名,文件默认为hostname.err(localhost.localdomain.err)。执行flushlogs;错误日志文件会重新加载。在my.cnf中添加 log-error=路径/文件名 来自定义错误日志文件。

    【查看错误日志的存储路径】
    通过错误日志可以见识系统的运行状态,便于即使发现故障、修复故障。mysql错误日志是以文本文件的形式存储的,可以使用文本编辑器直接查看;

    删除错误日志:
    mysql的错误日志是以文本文件的形式存储的,可以直接删除。
    在运行状态下删除错误日志文件后,则会自动创建。

    【刷新所有日志】

    一般查询日志:
    它记录了所有用户的操作,宝库启动和关闭服务、执行查询和更新语句等。mysql默认没有开启
    一般查询日志。如果需要可以修改my.cnf来开启。在my.cnf里添加log = /路径/文件名。一般查询
    日志是以文本格式文件存储的,日知名.Pid。 可以直接删除。开启一般查询并且mysql服务在
    运行状态下,删除了日志文件,它会自动创建新的。

    慢查询日志:
    慢查询日志是记录查询时长超过指定时间的日志。慢查询日志主要用来优化查询语句的。慢查询
    日志默认是关闭的,我们可以修改配置文件来开启:
    [mysqld]
    log-slow-queries //开启慢查询
    long_query_time = 1 //设置慢查询时间,默认10秒

    查看慢查询日志
    MySQL慢查询日志是以文本文件的形式存储的,可以直接使用文本编辑器查看。
    删除慢查询日志可以直接删除。删除后不再重启服务器的情况,需要执行
    mysqladmin -u root -p flush-logs 重新生成日志文件,或者在客户端登陆到服务器执行
    flush logs语句重建日志文件。

    MySQL主从复制概念MySQL主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接

    MySQL主从复制主要用途读写分离
    在开发工作中,有时候会遇见某个sql语句需要锁表,导致暂时不能使用读的服务,这样就会影响现有业务,使用主从复制,让主库负责写,从库负责读,这样即使主库出现了

    MySQL主从形式:一主一从、一主多从、多主一从、双主复制、
    一主一从和一主多从

    杜兴宇 16:04:50
    MySQL 主从复制概念MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
    MySQL 主从复制主要用途l 读写分离
    在开发工作中,有时候会遇见某个sql 语句需要锁表,导致暂时不能使用读的服务,这样就会影响现有业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运作。
    l 数据实时备份,当系统中某个节点发生故障时,可以方便的故障切换

    Mysql在3.25.15版本开启复制功能,mysql复制是将一个服务器(master)中的数据复制到其他服务器(slave)的过程。Mysql将存放DDL和DML的二进制日志发送到其他服务器上,然后从服务器(slave)将得到的二进制日志进行执行,从而保证主从服务器上的数据保持同步。
    l 高可用HA 读写分离,分担服务器的压力;
    l 架构扩展 并发量增大,我们可以通过增加主从服务器的数量来扩展并发。
    随着系统中业务访问量的增大,如果是单机部署数据库,就会导致I/O访问频率过高。有了主从复制,增加多个数据存储节点,将负载分布在多个从节点上,降低单机磁盘I/O访问的频率,提高单个机器的I/O性能。
    MySQL 主从形式:一主一从、一主多从、多主一从、双主复制、级联复制
    一主多从,提高系统的读性能

    一主一从和一主多从是最常见的主从架构,实施起来简单并且有效,不仅可以实现HA,而且还能读写分离,进而提升集群的并发能力。

    多主一从 (从5.7开始支持)

    双主复制
    双主复制,也就是互做主从复制,每个master既是master,又是另外一台服务器的slave。这样任何一方所做的变更,都会通过复制应用到另外一方的数据库中。
    级联复制

    级联复制模式下,部分slave的数据同步不连接主节点,而是连接从节点。因为如果主节点有太多的从节点,就会损耗一部分性能用于replication,那么我们可以让3~5个从节点连接主节点,其它从节点作为二级或者三级与从节点连接,这样不仅可以缓解主节点的压力,并且对数据一致性没有负面影响。

    MySQL 主从复制原理MySQL主从复制涉及到三个线程,一个运行在主节点(log dump thread),其余两个(I/O thread, SQL thread)运行在从节点,如下图所示:

    主节点 binary log dump 线程
    当从节点连接主节点时,主节点会创建一个log dump 线程,用于发送bin-log的内容。在读取bin-log中的操作时,此线程会对主节点上的bin-log加锁,当读取完成,甚至在发送给从节点之前,锁会被释放。
    l 从节点I/O线程
    当从节点上执行start slave命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的bin-log。I/O线程接收到主节点binlog dump 进程发来的更新之后,保存在本地relay-log中。
    l 从节点SQL线程
    SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。

    杜兴宇 16:05:24
    对于每一个主从连接,都需要三个进程来完成。当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个binary log dump 进程,而每个从节点都有自己的I/O进程,SQL进程。从节点用两个线程将从主库拉取更新和执行分成独立的任务,这样在执行同步数据任务的时候,不会降低读操作的性能。比如,如果从节点没有运行,此时I/O进程可以很快从主节点获取更新,尽管SQL进程还没有执行。如果在SQL进程执行之前从节点服务停止,至少I/O进程已经从主节点拉取到了最新的变更并且保存在本地relay日志中,当服务再次起来之后,就可以完成数据的同步。
    要实施复制,首先必须打开Master 端的binary log(bin-log)功能,否则无法实现。
    因为整个复制过程实际上就是Slave 从Master 端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。如下图所示:

    复制的基本过程如下:
    从节点上的I/O 进程连接主节点,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;主节点接收到来自从节点的I/O请求后,通过负责复制的I/O进程根据请求信息读取指定日志指定位置之后的日志信息,返回给从节点。返回信息中除了日志所包含的信息之外,还包括本次返回的信息的bin-log file 的以及bin-log position;从节点的I/O进程接收到内容后,将接收到的日志内容更新到本机的relay log中,并将读取到的binary log文件名和位置保存到master-info 文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log 的哪个位置开始往后的日志内容,请发给我”;Slave 的 SQL线程检测到relay-log 中新增加了内容后,会将relay-log的内容解析成在主节点上实际执行过的操作,并在本数据库中执行。
    MySQL 主从复制模式MySQL 主从复制默认是异步的模式。MySQL增删改操作会全部记录在binary log中,当slave节点连接master时,会主动从master处获取最新的bin log文件。并把bin log中的sql relay。
    l 异步模式(mysql async-mode)
    异步模式如下图所示,这种模式下,主节点不会主动push bin log到从节点,这样有可能导致failover的情况下,也许从节点没有即时地将最新的bin log同步到本地。

    l 半同步模式(mysql semi-sync)
    这种模式下主节点只需要接收到其中一台从节点的返回信息,就会commit;否则需要等待直到超时时间然后切换成异步模式再提交;这样做的目的可以使主从数据库的数据延迟缩小,可以提高数据安全性,确保了事务提交后,binlog至少传输到了一个从节点上,不能保证所有从节点将此事务更新到db中。性能上会有一定的降低,响应时间会变长。如下图所示:

    半同步模式不是mysql内置的,从mysql 5.5开始集成,需要master 和slave 安装插件开启半同步模式。
    l 全同步模式
    全同步模式是指主节点和从节点全部执行了commit并确认才会向客户端返回成功。

    杜兴宇 16:05:43
    binlog记录格式MySQL 主从复制有三种方式:基于SQL语句的复制(statement-based replication,SBR),基于行的复制(row-based replication,RBR),混合模式复制(mixed-based replication,MBR)。对应的binlog文件的格式也有三种:STATEMENT,ROW,MIXED。
    l Statement-base Replication (SBR)就是记录sql语句在bin log中,Mysql 5.1.4 及之前的版本都是使用的这种复制格式。优点是只需要记录会修改数据的sql语句到binlog中,减少了binlog日质量,节约I/O,提高性能。缺点是在某些情况下,会导致主从节点中数据不一致(比如sleep(),now()等)。
    l Row-based Relication(RBR)是mysql master将SQL语句分解为基于Row更改的语句并记录在bin log中,也就是只记录哪条数据被修改了,修改成什么样。优点是不会出现某些特定情况下的存储过程、或者函数、或者trigger的调用或者触发无法被正确复制的问题。缺点是会产生大量的日志,尤其是修改table的时候会让日志暴增,同时增加bin log同步时间。也不能通过bin log解析获取执行过的sql语句,只能看到发生的data变更。
    l Mixed-format Replication(MBR),MySQL NDB cluster 7.3 和7.4 使用的MBR。是以上两种模式的混合,对于一般的复制使用STATEMENT模式保存到binlog,对于STATEMENT模式无法复制的操作则使用ROW模式来保存,MySQL会根据执行的SQL语句选择日志保存方式。
    GTID复制模式@ 在传统的复制里面,当发生故障,需要主从切换,需要找到binlog和pos点,然后将主节点指向新的主节点,相对来说比较麻烦,也容易出错。在MySQL 5.6里面,不用再找binlog和pos点,我们只需要知道主节点的ip,端口,以及账号密码就行,因为复制是自动的,MySQL会通过内部机制GTID自动找点同步。
    @ 多线程复制(基于库),在MySQL 5.6以前的版本,slave的复制是单线程的。一个事件一个事件的读取应用。而master是并发写入的,所以延时是避免不了的。唯一有效的方法是把多个库放在多台slave,这样又有点浪费服务器。在MySQL 5.6里面,我们可以把多个表放在多个库,这样就可以使用多线程复制。
    基于GTID复制实现的工作原理主节点更新数据时,会在事务前产生GTID,一起记录到binlog日志中。从节点的I/O线程将变更的bin log,写入到本地的relay log中。SQL线程从relay log中获取GTID,然后对比本地binlog是否有记录(所以MySQL从节点必须要开启binary log)。如果有记录,说明该GTID的事务已经执行,从节点会忽略。如果没有记录,从节点就会从relay log中执行该GTID的事务,并记录到bin log。在解析过程中会判断是否有主键,如果没有就用二级索引,如果有就用全部扫描。
    总结Mysql 主从复制是mysql 高可用,高性能的基础,有了这个基础,mysql 的部署会变得简单、灵活并且具有多样性,从而可以根据不同的业务场景做出灵活的调整。

    MySQL的备份:
    1.备份的重要性:
    在生产环境中,为了防止硬件故障、软件故障、自然灾害、误操作等各种原因导致的数据库数据丢失后能恢复到事故之前的状态,我们需要对数据库进行备份和恢复操作。数据库的备份和恢复是非常重要的工作,数据的备份不是最终目的,数据的恢复才是;
    2.备份时应该注意的事项:
    1.最多能容忍多少数据丢失;决定了备份间隔时间、备份的方式;
    2.恢复数据需要在多长时间之内完成;备份方式、备份的工具;
    3.需要恢复哪些数据;决定了备份的内容;
    4.定期测试备份的可用性并提高恢复操作的效率;
    5.备份时的服务器负载;
    6.锁定资源的时长;

    备份的类型
    a.按照备份的数据集的范围分类:
    完全备份:整个数据集都进行备份;
    部分备份:数据集的一部分,比如部分表;

    b.按照数据的变化分类:
    全量备份:将整个mysql的所有库表进行备份;
    增量备份:仅备份自上一次完全备份或增量备份以来变量的那部分数据;
    差异备份:仅备份自上一次完成全量备份以来变量的那部分数据;

    c.按照操作对象分类:
    物理备份:直接从磁盘复制数据文件进行备份;
    逻辑备份:从数据库导出数据另存在一个或多个文本中,将数据转化为具体的sql语句;

    d.按照数据服务备份时的运行状态分类:
    热备:读写操作均可正常运行的状态下所做的备份;
    温备:可读但不可写状态下进行的备份;
    冷备:读写操作均不可进行,服务需要停止的状态下进行的备份。

    3.备份策略:
    备份策略一般都是 全量+差异+binlogs 或者是:全量+增量+binlogs。
    需要注意的是,如果需要更完整的备份数据,还需要依靠binlongs(二进制日志)。binlogs是mysql最重要的日志之一,他记录了所有的DDL和DML,以事件的形式记录,这里强烈建议在生产环境中,将数据与二进制日志分开存放并对二进制日志也做备份。

    4.mysql备份工具:
    (1)mysqldump:mysql服务自带的备份工具,mysqldump是一个逻辑备份工具,mysqldump的本质是将数据库转为可执行sql脚本,文件名以sql结尾。可以用来做完全备份和部分备份。
    支持InnoDB存储引擎的热备份功能,MyISAM存储引擎的温备功能。

    (2)系统自带的cp/tar工具:这是一种物理备份,它属于冷备份,需要注意的是不能仅仅备份数据,要同时备份事务日志,并且要求数据和日志在同一逻辑卷。

    (3)xtrabackup:由Percona开发的很强大的开源工具,支持对InnoDB做热备,物理备份工具。

    (4)mysql hotcopy:通过复制库表目录来实现mysql的备份;

    mysqldump的语法:
    备份:mysqldump -u root -p 库 表>路径/文件名.sql
    1.对单个库进行备份:
    mysqldump -u user -p databasename> /路径/文件名.sql
    2.对单个库中的表进行备份:
    mysqldump -u user -p databasename tablename1 tablename2 tablename3…> /路径/文件名.sql

    3.对多个库进行备份:
    mysqldump -u user -p -B/–databases 库1 库2 库3…>/路径/文件名.sql

    4.对所有库的所有内容进行备份:
    mysqldump -u user -p -A/–databases > /路径/文件名.sql

    还有几个参数:
    -R 导出存储过程和自定义函数;
    -t 只备份数据而不备份表结构;
    -d 只备份表结构,不备份数据;
    –lock-table 在备份时进行锁表;
    –add-locks 在执行insert之前和之后进行锁表
    –default-character-set 字符串 指定字符集
    –single-transaction 备份期间不会锁表也不会组织任何的事务;

    注意!【在命令行创建一个路径:mkdir /zhy】

    备份恢复:
    第一种方法:
    1.在mysql里面:CREATE DATABASE databasename;
    2.在命令行执行:mysql -u user -p databasename < /备份路径/文件名.sql
    第二种方法:
    1.CREATE DATABASE databasename;
    2.USE databasename;
    3.source /备份路径/文件名.sql

    第二种:cp/tar 这是一种冷备份:他需要关闭服务情况下才行。
    冷备份的优点:
    1.非常快速的备份方法(直接拷贝文件);
    2.容易归档(简单拷贝即可)
    3.容易恢复到某个时间点上(只需要将文件在拷贝回去);
    4.低度维护,告诉安全。

    缺点:
    1.单独使用时,只能提供到’某个时间点上’的恢复。
    2.备份和还原的全过程必须停止服务;
    3.若磁盘空间有限,只能拷贝到外部存储设备上,速度会慢。
    4.不能按表或者用户来还原数据。

    第三种:mysqlhotcopy:适用于MyISAM引擎,不适用于InnoDB。它是属于热备,而且速度快 ,适合数据量大的数据库备份;

    原理:它使用LOCK TABLES,FLUSH TABLE和cp或者scp来快速备份数据库。
    他是备份数据库或单个表的最快的途径。

    mysqlhotcopy 他是perl语言一个工具,所以它需要per的支持:
    yum -y install per per-DBI perl-DBI-MySQL
    备份语法:
    mysqlhotcopy -u user -p ‘password’ db_name tablename /备份路径/文件名

    还原语法:
    cp -R /备份路径/文件名 /var/mysql/data
    chown -R /var/mysql/data
    重启服务;

    冷备份:在数据库关闭状态下进行备份操作。
    热备份:早数据库处于运行时进行备份操作,该备份方法依赖数据库的日志文件。
    温备份:数据库锁定表格(不可写入但可读)的状态下进行备份操作。

    MySQL的优化:
    mysql性能优化就是通过合理安排资源,调整系统参数使mysql运行更快、
    更节省资源,mysql优化,一方面是找出系统瓶颈,提高mysql数据库整体的性能,,另一方面需要合理的结构设计和参数调整,以提高用户操作响应的速度,同时还要尽可能节省系统资源,以便系统可以提供更大负荷的服务,mysql数据库优化是多方面的,原则是减少系统的瓶颈,减少资源的占用,提高系统反应速度,包含,性能优化、查询优化、数据库结构和mysql服务器优化。

    mysql中可以使用SHOW STATUS语句查询一些mysql数据库的性能参数。
    SHOW STATUS LIKE ‘value’;
    value指的是性能参数;
    1.connection,连接mysql服务器的次数;
    2.update,mysql服务器上线的时间;
    3.slow_queries,慢查询的次数;
    4.com_insert,插入操作的次数。
    5.com_select,查询的次数;
    6.com_update,更新的次数;
    7.com_delete,删除操作的次数;

    设置最大连接数:
    SET GLOBAL MAX_CONNECTIONS=5000;
    最大可以设置16384,超过了没用

    查看当前被使用的connection
    show variables like max_user_connections;

    分析查询语句:
    通过分析查询语句,可以了解查询语句执行的情况,找出查询语句的瓶颈,从而优化查询语句。
    mysql中提供了EXPLAIN语句和DESCRIBE(可以缩写为DESC)语句,来分析查询语句。

    EXPLAIN的语法:
    EXPLAIN [EXTENDED]SELECT options;
    EXTENDED 关键字,EXPAIN语句会产生附加信息;options是select语句的查询选项,包括from、where子句等等。
    执行这个语句可以分析EXPLAIN 后面的查询语句的执行情况,并且能够分析出所查询的表的一些特征。
    mysql>EXPLAIN SELECT * FROM db_info;

    1.SIMPLE(simple)表示简单查询,其中不包括子查询和连接查询;
    2.PRIMARY(primary)表示主查询,或者是最外层的查询语句;
    3.UNION(union)表示连接查询的第2个或者后面的查询语句。
    4.DEPENDENT UNION(dependent union)表示连接查询中的第二个或者后面的select语句,取决于外面的查询。
    5.UNION RESULT 表示连接查询的结果;
    6.SUBQUERY 表示子查询的第1个select语句;
    7.DEPENDENT SUBQUERY 子查询的第1个select,取决于外面的查询;
    8.DERIVED 表示导出表的select(from子句的查询)。

    c.type:表示连接类型:
    1.ALL:对于前面的表的任意的行组合,进行完整的表扫描。通常可以增加更多的索引来避免使用all连接;
    2.index,它只扫描索引数,而不是全表数据,通常比ALL 类型要快,因为索引文件通常比数据文件小;
    3.system,表示仅有一行的系统表。是const连接类型一个特例。
    4.const:数据表最多只有一个匹配行,他将在查询开始时被读取,并在余下的查询优化中作为常量对待。const表查询速度很快,因为它只读一次。const与使用常数值比如primary key 或者union索引的所有部分的场合。
    mysql>explain select * from db_info WHERE id=2;

    5.eq_ref:对于某个来自前面的表的行组合,从该表中读取一行。当一个索引的所有部分都在查询中使用并且索引是unique或primary key时候即可使用这种类型,eq_ref 可以用于使用‘=’操作符比较带索引的列,比较值可以为常量或者一个在该表前面所读取的表的列的表达式。
    EXPLAIN SELECT * FROM user,db_info WHERE user.com_id_info.com_id;
    6.RE对于来自前面的表的任意行组合,将从该表中读取所有匹配行,这种类型用于所既不是unique也不是primary key 的情况,或者查询中使用了所引例的左子集,即索引中左边的部分组合ref可以用于使用=或者<=>操作符的带索引的列。

    7.ref_or_null,该链接类型是如果是ref类型,但是添加了mysql可以专门搜索包含null值得行,在解决子查询中经常使用该链接类型得优化;

    8.index_merge:该链接类型表示使用了索引合并优化方法,在这种情况下,key列包含了使用得索引得清单,key_len包含了 使用得索引得最长得关键元素;

    9.index_subquery,:该链接类型类似于unique_subquery,可以替换in子查询,但是只适合下列形式得子查询中非唯一索引。

    10.range:只检索给定范围得行,使用一个索引来选择行。key列显示使用得那个索引。key_len包含所使用得最长关键元素。当使用=,<>,<=,is null, <=>, between或者in操作符,用常量比较关键字列时,类型为range。

    possible_keys:它列出的是mysql能使用哪个索引在该表中找到行。如果该列是null,则没有相关的索引,在这种情况下,可以通过检查 where子句看他是否引用某些列或者适合索引的列来提高查询性能,如果是这样,可以创建适合的索引来提高查询的性能。

    ref:表示使用哪个列或者常熟或者索引一起来查询记录。

    rows:显示mysql在表中进行查询必须检查的行数。

    extra:显示mysql在处理查询时的详细信息。

    DESCRIBE语句和EXPLAIN语句的用法以及效果一样。

    索引对于查询速度的影响:
    mysql中提高性能的最有效的方式就是对数据表设计合理的索引,索引提供了高效的方法。
    因此,索引对查询的速度有着至关重要的影响。使用所有可以快速的定位的某条记录,从而调高数据库的查询速度,提高数据库的性能,如果查询的时候没有使用索引,mysql将扫描全表的所有记录。在数据量大的情况下,这样的查询的速度会很慢。如果使用索引进行查询,查询语句可以依据索引快速定位到待查询的记录,从而减少查询的记录数,达到提高查询速度的目的。

    使用索引的几种特殊情况:
    1.使用like关键字的查询语句。如果匹配字符串的第一个字符为‘%’,索引不会起作用。只有‘%’不在第一个位置的时候,索引才会起到作用。
    mysql> EXPLAIN SELECT * FROM db_info WHERE name LIKE ‘%jack’;
    ±—±------------±--------±-----±--------------±-----±--------±-----±-----±------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    ±—±------------±--------±-----±--------------±-----±--------±-----±-----±------------+
    | 1 | SIMPLE | db_info | ALL | NULL | NULL | NULL | NULL | 3 | Using where |
    ±—±------------±--------±-----±--------------±-----±--------±-----±-----±------------+
    1 row in set (0.00 sec)

    mysql> EXPLAIN SELECT * FROM db_info WHERE name LIKE ‘jack%’;
    ±—±------------±--------±------±--------------±------±--------±-----±-----±------------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
    ±—±------------±--------±------±--------------±------±--------±-----±-----±------------+
    | 1 | SIMPLE | db_info | range | in_dx | in_dx | 62 | NULL | 1 | Using where |
    ±—±------------±--------±------±--------------±------±--------±-----±-----±------------+
    1 row in set (0.00 sec)

    2.使用多组合引的查询语句,一个组合索引最多可以包含16个字段,对于组合索引,只有查询条件中使用了最左边的索引字段,

    3.使用or关键字的查询语句。查询条件中有or关键字,且or前后的两个条件中的字段都有索引时,查询中才使用索引,否则,查询将不适用索引。

    优化数据库表结构:
    分库和分表:
    垂直分和水平分:
    什么时候需要分库:当一个库里面的数量很多时,并且查询率很高,为了降低单个库的负荷,我们把一个库里面的表按照不同的业务类型放到多个库里面,这个叫做垂直分,水平分指库里面的表的数据量特别大,我们把同一个表里不常用的字段给他分离到其他库里面,
    什么时候分表:当一个数据库里面的字段和数量特别庞大的时候,为了提高查询速度,我们根据业务把不同的字段分到多个表里,这个叫垂直分表。把一个表里的数据从一个位置分离到多个表里。

    优化插入数据的速度:
    (1)禁止索引:alter table 表名 disable keys;
    (2)禁用唯一性检查:set unique_checks=0 (1开启,0禁用);
    (3)禁用外键检查:set foreign_checks=0;
    (4)尽量自动提交:set autocommit=0;
    (5)尽量使用批量插入:insert into db_info(name,sex)value(‘lucy’,2),(‘tom’,1),(‘jack’,男);
    (6)

    第一章:初识redis
    redis(Remote dictionary server)是一个开源(BSD许可),是一种基于键值对(key-value)的NoSQL数据库,redis是一个内存存储结构的服务器,可以做告诉缓存和消息列队代理。
    与很多键值对数据库不同的是,redis支持字符串(string)、哈希表(hash)、列表(list)、集合(set)、有序集合(zset)、位图(bitmaps)、Hyperloglogs、GEO等数据结构和算法组成,因此redis可以满足很多的应用场景,而且因为redis会将数据存放在内存中,所以它的读写速度非常惊人。读:110000/s 写:85000/s 不仅如此,redis还可以将内存中的数据利用快照和日志的形式保存到磁盘上,这样在发生断电或者机器故障的时候,内存中的数据不会‘丢失’。
    redis还提供了键过期、流水线、哨兵、内置复制、lua脚本语言、LRU收回、事务、同时通过redis sentinel 提供高可用,通过redis cluster 提供自动分区。

    redis的特性:
    1.速度快:
    正常情况下,redis执行命令的速度非常快,读:110000/s 写:80000/s
    为什么快?
    (1)把数据存放在内存中,是redis速度快的主要原因;
    (2)redis是用C语言编写的,一般来说C语言实现的程序‘距离’ 操作系统更近,执行速度更快;
    (3)redis使用了单线程架构,预防了多线可能产生的竞争问题。

    2.基于键值对的数据结构服务器:
    几乎所有的编程语言都提供了类似字典的功能,例如java里的map,Python里的dict,类似于这种组织数据的方式,与很多键值对数据库不同的是,redis中的值不仅可以是字符串,而且还可以是具体的数据结构,这样不仅能便于在许多应用场景的开发,同时也能够提高开发效率。
    主要的数据结构有5种:
    字符串(string)、哈希表(hash)、列表(list)、集合(set)、有序集合(zset)、
    同时在字符串的基础上演变出了位图和Hyperloglog这两种神奇的数据结构,并且随着LBS(loclation based server基于位置服务)的不断发展,redis3.2版本中加入有关GEO(地理信息定位的功能,总之在这些数据结构的帮助下,开发者可以开发出各种’有意思’的应用)

    3.丰富的功能:
    除了多种数据结构,redis还提供了许多额外的功能:
    (1)提供了键过期功能,还可以来实现缓存;
    (2)提供了发布订阅功能,可以来实现消息系统;
    (3)支持Lua脚本功能,可以利用Lua创造出心得redis命令;
    (4)提供了简单得事务功能,能在一定程度上保证事务特性;
    (5)提供了流水线(Pipeline)功能,这样客户端能将一批命令一次性传到redis,减少了网络得开销;

    4.简单稳定:
    redis的简单主要表现在三个方面,首先,redis的原码很少,早期版本只有2万,3.0版本后添加了集群特性,代码增至5万行左右,相对于很多NoSQL数据库来说代码量要少很多。其次redis,redis使用单线程模型,这样不仅使redis服务端处理模型变得简单,而且也是使用客户端开发变得简单,最后redis不需要依赖于操作系统中的类库(例如Memcache需要依赖libevent这样的系统类库),redis自己实现了事件处理的相关功能。

    5.客户端语言多:
    redis提供了简单的TCP通信协议,很多编程语言可以很方便地介入redis,并且由于redis受到社区和大公司的广泛认可,所以支持redis的客户端语言也非常多,几乎涵盖了主流的编程语言,
    例如:java、php、python、C、C++、Nodejs等;

    6.持久化:
    通常看,将数据放在内存中是不安全的,一旦发生断电或者机器故障,重要的数据可能丢失,因此redis提供了两种持久化方式:RDB和AOF,即可以用两种策略将内存数据保存到磁盘中,这样就保证了数据的持久性;

    7.主从复制:
    redis提供了复制功能,实现了多个相同数据的redis副本,复制功能是分布式redis的基础。

    8.高可用和分布式
    redis从2.8版本正式提供高可用实现redis sentinel,它能够保证redis节点的故障发现和故障自动转移,redis从3.0版本正式提供了分布实现redis cluster,他是redis真正的分布式实现,提供了高可用、读写和容量的扩展性。

    redis的使用场景:
    1.缓存
    缓存机制几乎在所有的大型网站都有使用,合理地使用缓存不仅可以加快数据的访问速度,而且能够有效的降低后端数据源的压力。redis提供了键值对过期时间设置,并且也提供了灵活控制最大内存和存溢出后的淘汰策略,可以这么说,一个合理的缓存设计能够称谓一个网站的稳定保驾护航。

    2.排行榜系统:
    排行榜系统几乎存在于所有的网站,例如按照热搜度的排行榜,按照发布时间的排行榜,按照各种复杂维度计算出的排行榜,redis提供了列表和有序合数架构,合理地使用这些数据结构,可以很方便的构建各种排行系统。

    3.计算器的应用:
    计算器在网站中的作用至关重要,例如视屏网站有浏览数,为了保证数据的实时性,每次播放和浏览要做加1的操作,如果并发量很大对于传统关系数据库的性能是一种挑战,redis天然支持技术功能而且计数的性能也非常好,可以i说是计算器系统的重要选择。

    4.社交网络:
    赞/踩、粉丝、共同好友/喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常比较大,而且传统的关系型数据库不太适合保存这种类型的数据,redis提供的数据结构可以相对容易地实现这些功能。

    5.消息列队系统:
    消息列队系统可以说是一个大型网站的必备基础组件,因为其具有业务解耦、非实时业务肖峰等特征。redis提供了发布订阅功能和阻塞队列的功能,虽然和专业的消息队列比还不够强大,但是对于一般的消息队列功能基本可以满足。

    redis的缺点:
    实际上任何一门技术都一样,他都有自己的应用场景和边界,也就是说redis不是万能的,有很多问题也是redis不适合解决的。我们从数据的规模和冷热的角度来分析:
    站在数据规模的角度看,数据可以分为大规模和小规模,我们redis将数据存储在内存中,虽然目前内存的价格已经相对便宜了,但是数据量太大,例如每天有几亿的用户行为数据,使用redis的话,基本是无底洞,经济成本会非常高。
    站在数据冷热的角度看,数据分冷数据和热数据,热数据就是需要频繁操作的数据,反之为零冷数据。例如对于视频网站来说,视频基本信息在各个业务线都是经常操作的数据,而用户的观看记录不一定经常需要访问,所以视频信息就属于热数据,而用户观看记录属于冷数据。如果将冷数据也放在redis里,就会造成对于内存资源的浪费,但是对于热数据,就可以放在redis中加速读写,也可以减轻后端存储的负载,可以说是事半功倍。
    所以redis的使用也要根据实际情况来决定。

    第二章 redis得全局命令和数据结构

    安装目录下src/里面的可执行命令:
    redis-server 启动redis服务的命令

    redis-cli 启动redis客户端的

    resis-server redis的哨兵服务

    redis-check-aof redis-check-rdb 持久化文件的检查修复

    redis-benchmark redis的基准测试工具

    redis的日志级别:debug、varbose、notice、warning
    debug:记录很多信息,用于开发和测试
    varbose:有用的信息,比debug记录的信息少
    notice:普通的varbose,常用于生产环境
    warning:只有非常重要的信息会记录到日志

    redis的全局命令:

    keys * 查看所有的键
    dbsize 统计键的总和(个数)
    exists ‘key’ 判断这个key是否存在,返回1表示存在,返回0表示不存在
    del key1 key2 … 删除键值对

    键过期:
    1.set key value [EX seconds] [PX milliseconds] 给新添加的键值对设置过期时间
    2.expire key seconds 给已有的键值对设置过期时间
    ttl key 查看键的过期时间,返回+数表示还有多少时间过期,返回-1表示未给这个key设置过期时间,返回-2表示这个key已经过期,并且被删除或者是这个键就不存在了。

    redis的数据类型:
    1.string(字符串):
    字符串类型是redis最基础的数据结构,首先键都是字符串类型,而且其他几种数据结构都是在字符串类型的基础上构建的,所以字符串类型能为其他四种数据结构的学习奠定基础。字符串实际上可以是字符串(简单的字符串、复杂的字符串),也可以是数字,甚至是二进制(图片、音频、视频),但是最大不能超过512M。
    命令格式:
    set key value [ex seconds] [px mileseconds] [nx|xx]

    [ex seconds] 为键设置过期时间,单位是秒

    [px mileseconds] 单位是毫秒

    nx 键必须不存在,才可以设置成功,用于添加;

    xx 键必须存在,才可以设置成功,用于更新;
    命令:
    setnx key value [xx]
    setnx这个命令在新添加键值对的时候非常有用,它能够避免我们把已有键的值误修改。返回0说明这个键已存在,并且我们的命令不会被执行;返回1,说明这个键不存在,键值对添加成功。

    获取值的命令:get key

    批量设置键值对:
    mset key1 value1 key2 value2…
    例:mset a 1 b 2 c 3 d 4

    计数:
    incr key
    incr只能对数字自增
    值不是整数的时候,返回错误,值是整数,返回整数+1,如果键不存在,按0开始自增,返回结果是1
    列:
    127.0.0.1:6379> incr a
    (integer) 2
    127.0.0.1:6379> get a
    “2”
    127.0.0.1:6379> incr a
    (integer) 3
    127.0.0.1:6379> get a
    “3”
    127.0.0.1:6379> incr f
    (integer) 1
    127.0.0.1:6379> incr f
    (integer) 2
    127.0.0.1:6379> incr f
    (integer) 3
    127.0.0.1:6379> get f
    “3”

    decr key(自减)
    例:
    127.0.0.1:6379> decr f
    (integer) 2
    127.0.0.1:6379> decr f
    (integer) 1
    127.0.0.1:6379> decr f
    (integer) 0
    127.0.0.1:6379> decr f
    (integer) -1
    127.0.0.1:6379> decr f
    (integer) -2
    127.0.0.1:6379> keys *

    1. “a”
    2. “e”
    3. “f”
    4. “b”
    5. “c”
    6. “d”
      127.0.0.1:6379> decr g
      (integer) -1
      127.0.0.1:6379> decr g
      (integer) -2
      如果这个键不存在,那就从0开始递减,返回结果是-1

    incrby key 数字 (自增指定数字)
    例:
    127.0.0.1:6379> incrby a 5
    (integer) 6
    127.0.0.1:6379> incrby a 5
    (integer) 11
    127.0.0.1:6379> incrby h 5
    (integer) 5
    127.0.0.1:6379> incrby h 5
    (integer) 10
    127.0.0.1:6379>
    如果这个键不存在,从0开始增加

    decrby key 数字 (自减指定个数字)

    incrbyfloat key 小数 (带小数点的数)
    例:
    127.0.0.1:6379> incrbyfloat h 1.5
    “11.5”
    127.0.0.1:6379> incrbyfloat h 1.5
    “13”
    127.0.0.1:6379> incrbyfloat h 1.5
    “14.5”
    没有自减小数的命令

    append key value 追加值:相当于在原在值后面再加上现在的值
    例:
    127.0.0.1:6379> set hello world
    OK
    127.0.0.1:6379> append hello friends
    (integer) 12
    127.0.0.1:6379> get hello
    “worldfriends”

    strlen key 返回这个key他的值的字符串长度
    例:
    127.0.0.1:6379> strlen hello
    (integer) 12

    设置key的新值,返回原值
    getset key value
    例:
    127.0.0.1:6379> strlen hello
    (integer) 12

    setrange key value的位置下标 value 把key的值的某一个位置上的字符改为value
    例:
    127.0.0.1:6379> get hello
    “world”
    127.0.0.1:6379> setrange hello 0 x
    (integer) 5
    127.0.0.1:6379> get hello
    “xorld”

    用 value 参数覆写(overwrite)给定 key 所储存的字符串值,从偏移量 offset 开始。
    不存在的 key 当作空白字符串处理。
    SETRANGE 命令会确保字符串足够长以便将 value 设置在指定的偏移量上,如果给定 key 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的 offset 是 10 ),那么原字符和偏移量之间的空白将用零字节(zerobytes, “\x00” )来填充。
    注意你能使用的最大偏移量是 2^29-1(536870911) ,因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内。如果你需要使用比这更大的空间,你可以使用多个 key 。
    当生成一个很长的字符串时,Redis 需要分配内存空间,该操作有时候可能会造成服务器阻塞(block)。在2010年的Macbook Pro上,设置偏移量为 536870911(512MB 内存分配),耗费约 300 毫秒, 设置偏移量为 134217728(128MB 内存分配),耗费约 80 毫秒,设置偏移量 33554432(32MB 内存分配),耗费约 30 毫秒,设置偏移量为 8388608(8MB 内存分配),耗费约 8 毫秒。 注意若首次内存分配成功之后,再对同一个 key 调用 SETRANGE 操作,无须再重新内存。

    哈希:
    几乎所有的编程语言都提供了哈希(hash)类型,他们的叫法可能是哈希、字典、关联数组等。
    在redis中,哈希类型是指键值本身又是一种键值对结构,例如value=[field,vlue1 field2 value2…fieldN valueN]
    哈希类型中的映射关系叫做field-value,这里的value是指field对应的值,不是键对应的值。

    命令:
    1.设置值
    hset key field1 value1 fiels2 value2…
    127.0.0.1:6379> hset redis a 1 b 2 c 3
    (integer) 3
    127.0.0.1:6379> hset redis d 4
    (integer) 1

    2.获取值:
    hget key filed
    例:
    127.0.0.1:6379> hget redis a
    “1”
    127.0.0.1:6379> hget redis c
    “3”
    127.0.0.1:6379> hget redis
    (error) ERR wrong number of arguments for ‘hget’ command
    127.0.0.1:6379> hget redis b
    “2”
    key后面必须跟field 并且只能跟1个field

    3.删除值:
    hdel key field1 field2…
    127.0.0.1:6379> hdel redis a b c
    (integer) 3

    4.hlen key 计算key里面field的个数
    127.0.0.1:6379> hlen redis
    (integer) 1

    5.批量设置和获取field value
    hmset
    127.0.0.1:6379> hmset hello a 1 b 2 c 3
    OK
    127.0.0.1:6379> hmget hello a b c

    1. “1”
    2. “2”
    3. “3”

    6.判断key里面是否存在field
    hexists key field 返回1代表有。返回0代表没有
    127.0.0.1:6379> hexists hello a
    (integer) 1
    127.0.0.1:6379> hexists hello b
    (integer) 1
    127.0.0.1:6379> hexists hello d
    (integer) 0

    7.获取所有的field
    hkeys key
    例:
    127.0.0.1:6379> hkeys hello

    1. “a”
    2. “b”
    3. “c”

    8.获取所有的值
    hvals key
    例:
    127.0.0.1:6379> hvals hello

    1. “1”
    2. “2”
    3. “3”
      9.hgetall key 获取key里面每组field和value
      127.0.0.1:6379> hgetall hello
    4. “a”
    5. “1”
    6. “b”
    7. “2”
    8. “c”
    9. “3”

    10.hincrby key field 数字 使key里面field的值自增的指定的数字
    127.0.0.1:6379> hincrby hello a 4
    (integer) 5
    127.0.0.1:6379> hget hello a
    “5”

    11.计算value的字符串长度:
    hstrlen key field
    127.0.0.1:6379> hstrlen hello a
    (integer) 1

    list列表:
    列表类型是用来存储多个有序的字符串,比如a,b,c,e五个元素从左到右组成了一个有序的列表,列表中的每个字符串称为元素,一个列表最多可以存储2^32-1个元素。在redis中,可以对列表两端进行插(push)和删除(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等,列表是一种比较灵活的数据结构。

    列表类型有两个特点:第一、列获取表中的元素是有序的,这就意味着可以通过索引下标某个元素或者某个范围内的元素列表;第二、列表中的元素可以是重复的。

    命令:
    1.lpush 在列表的最左端添加元素,rpush 在列表的最右端添加元素,
    linsert 在已有列表某个元素的前面或后面添加新的元素。

    lpush key value1 value2…
    rpush key value1 value2…
    linsert key before | after pivot value
    例:
    127.0.0.1:6379> lpush list a b c
    (integer) 3
    127.0.0.1:6379> rpush list2 a b c
    (integer) 3
    127.0.0.1:6379> lrange list 0 -1

    1. “c”
    2. “b”
    3. “a”
      127.0.0.1:6379> lrange list2 0 -1
    4. “a”
    5. “b”
    6. “c”
      127.0.0.1:6379> linsert list2 before b d
      (integer) 4
      127.0.0.1:6379> linsert list2 after c e
      (integer) 5
      127.0.0.1:6379> lrange list2 0 -1
    7. “a”
    8. “d”
    9. “b”
    10. “c”
    11. “e”

    2.查看列表
    (1)lrange key start end 查看指定范围的列表元素
    127.0.0.1:6379> lrange list2 1 3

    1. “d”
    2. “b”
    3. “c”
      (2)lindex key index 查看指定索引下标的元素

    (3)llen key 获取列表的长度

    3.删除:

    lpop 从左边删除1个元素
    rpop 从右边删除1个元素

    lrem key count(数字) value
    count>0 从左往右删,删除count范围内的这个value,如果范围内没有这个value,则不删;
    count<0 从右往左删,删除count范围内的这个value,如果范围内没有这个value,则不删;
    count=0 删除列表中所有和value相等的元素;
    例:
    127.0.0.1:6379> lrange list2 0 -1

    1. “b”
    2. “a”
    3. “b”
    4. “c”
    5. “d”
    6. “c”
    7. “b”
    8. “e”
    9. “d”
    10. “f”
    11. “a”
    12. “b”
    13. “c”
    14. “d”
    15. “a”
    16. “b”
    17. “c”
      127.0.0.1:6379> lrem list2 1 a
      (integer) 1
      127.0.0.1:6379> lrange list2 0 -1
    18. “b”
    19. “b”
    20. “c”
    21. “d”
    22. “c”
    23. “b”
    24. “e”
    25. “d”
    26. “f”
    27. “a”
    28. “b”
    29. “c”
    30. “d”
    31. “a”
    32. “b”
    33. “c”
      127.0.0.1:6379> lrem list2 -1 a
      (integer) 1
      127.0.0.1:6379> lrange list2 0 -1
    34. “b”
    35. “b”
    36. “c”
    37. “d”
    38. “c”
    39. “b”
    40. “e”
    41. “d”
    42. “f”
    43. “a”
    44. “b”
    45. “c”
    46. “d”
    47. “b”
    48. “c”
      127.0.0.1:6379> lrem list2 0 b
      (integer) 5
      127.0.0.1:6379> lrange list2 0 -1
    49. “c”
    50. “d”
    51. “c”
    52. “e”
    53. “d”
    54. “f”
    55. “a”
    56. “c”
    57. “d”
    58. “c”

    4.lset key index newvalue 修改指定下标的元素为newvalue
    例:
    127.0.0.1:6379> lset list2 2 java
    OK
    127.0.0.1:6379> lrange list2 0 -1

    1. “c”
    2. “d”
    3. “java”
    4. “e”
    5. “d”
    6. “f”
    7. “a”
    8. “c”
    9. “d”
    10. “c”

    5.阻塞操作 blpop brpop 并发太大的时候,用阻塞的方法缓解服务器的压力。
    blpop key1 key2… timeout 从第一个列表的最左边开始,弹出一个元素,返回列表名称和被删除的元素,如果所有列表中都没有元素了,那就会阻塞timeout秒,然后返回’nil’ 和阻塞的时间;

    blpop key1 key2… timeout 从第一个列表的最右边开始,弹出一个元素,返回列表名称和被删除的元素,如果所有列表中都没有元素了,那就会阻塞timeout秒,然后返回’nil’ 和阻塞的时间;

    127.0.0.1:6379> rpush list a b c d
    (integer) 4
    127.0.0.1:6379> brpop list list2 3

    1. “list”
    2. “d”
      127.0.0.1:6379> brpop list 3
      (nil)
      (3.08s)

    6.集合:(set)类型也是用来保存多个字符串元素,但和列表类型不同的是,集合中不允许有重复的元素,并且集合中的元素是无序的,不能通过索引下标获取元素,一个集合最多可以存储2^32-1个元素,redis处理支持集合内的增删改查,同时还支持多个集合取交集、并集、差集。
    a=[0,2,3] b=[2,3,4,5,6,7,8]

    命令:
    1.往集合里添加元素:sadd key value1 value2… 注意:添加重复的元素只能添加进去一个;

    127.0.0.1:6379> sadd set1 a b c d
    (integer) 4
    127.0.0.1:6379> sadd set1 e e
    (integer) 1
    127.0.0.1:6379> sadd set1 a b
    (integer) 0

    2.删除元素:srem key value
    127.0.0.1:6379>srem set1 a
    (integer) 1

    3.显示集合中元素的个数:scard key
    127.0.0.1:6379>scard set1
    (intrger)4

    4.判断元素是否在这个集合中:
    sismember key value 返回1,表示有这个元素,返回0表示没有。

    5.随机从集合中返回指定个数的元素:
    srandmember key [count] 不写count就返回1

    6.从集合中随机删除元素:
    spop key [count] 不写count默认是1

    7.查看集合内所有元素:
    smember key

    集合间的操作:
    1.求多个集合的交集:
    sinter key1 key2…
    例:
    127.0.0.1:6379> sadd set 1 2 3 4 5 6
    (integer) 6
    127.0.0.1:6379> sadd set1 1 3 5 6 8 9 10
    (integer) 7
    127.0.0.1:6379> sinter set set1

    1. “1”
    2. “3”
    3. “5”
    4. “6”

    2.求多个集合的并集:sunion key1 key2…
    例:
    127.0.0.1:6379> sunion set set1

    1. “1”
    2. “2”
    3. “3”
    4. “4”
    5. “5”
    6. “6”
    7. “8”
    8. “9”
    9. “10”

    2.求多个集合的差集:sdiff key1 key2
    例:
    127.0.0.1:6379> sdiff set set1

    1. “2”
    2. “4”

    将多个集合中的交集、并集、差集作为集合保存到redis当中:
    sinterstore destination key1 key2…
    sunionstore destination key1 key2…
    sdiffdtore

    5.有序集合:
    有序集合相对于哈希、列表、集合来说算是比较陌生的一种数据结构,但是他和我们这些熟悉的数据类型有很多联系,它保留了集合不能有重复值的特性,但不同的是,有序集合里边的元素是可以排序。他和列表使用下标的方式排序不同,它给每个元素设置了一个分数(score)作为排序依据,合理的利用有序集合,能帮助我们在实际开发中解决很多问题。

    命令:
    1.添加成员:zadd key 【NX|XX】[CH] [INCR] score member [score member…]
    NX:必须不存在才可以设置,用于添加;
    XX:必须存在才可以设置,用于更新;
    INCR:对分数做增加,zincrby 可以自定义增加的分数;
    CH:此次操作完成后,有序集合元素和分数变化的个数;

    2.计算成员的个数:zcard key

    3.求成员的分数:
    zscore key member

    4.求成员的排名(根据分数):
    (1)zrank key member 按照分数由低到高排
    (2)zrevrank key member 按照分数由高到低排(返回位置信息是从0开始的);
    127.0.0.1:6379> zrank zset1 c
    (integer) 2
    127.0.0.1:6379> zrank zset1 a
    (integer) 0

    5.删除成员:
    zrem key member1 member2…

    6.增加某个成员的分数:
    zincrby key increment member 若次成员不存在,则会添加此成员并且它的分数就是
    increment
    127.0.0.1:6379> zincrby zset1 3 a
    “4”
    127.0.0.1:6379> zscore zset1 a
    “4”
    127.0.0.1:6379> zincrby zset1 5 e
    “5”
    127.0.0.1:6379> zscore zset1 e
    “5”
    7.指定排名范围的成员:
    zrange key start end [withscores] 由低到高
    zrevrange key start end [withscores] 由高到低
    127.0.0.1:6379> zrange zset1 0 3 withscores

    1. “b”
    2. “2”
    3. “c”
    4. “3”
    5. “a”
    6. “4”
    7. “d”
    8. “4”

    127.0.0.1:6379> zrevrange zset1 1 3 withscores

    1. “d”
    2. “4”
    3. “a”
    4. “4”
    5. “c”
    6. “3”
      127.0.0.1:6379> zrevrange zset1 1 3
    7. “d”
    8. “a”
    9. “c”

    8.指定分数范围内的成员排名:
    zrangebyscore key minscore maxscore [withscores] [limit offset count] 由低到高
    zrevrangebyscore key minscore maxscore [withscores] [limit offset count] 由低到高
    [limit offset count] 限制输出的起始位置和个数
    127.0.0.1:6379> zrangebyscore zset1 1 10 withscores

    1. “b”
    2. “2”
    3. “c”
    4. “3”
    5. “a”
    6. “4”
    7. “d”
    8. “4”
    9. “e”
    10. “5”
      127.0.0.1:6379> zrevrangebyscore zset1 3 1 withscores
    11. “c”
    12. “3”
    13. “b”
    14. “2”

    minscore 和 maxscore 可以选择-inf(无限小)+inf(无限大)
    127.0.0.1:6379> zrangebyscore zset1 200 +inf withscores

    1. “g”
    2. “201”
    3. “f”
    4. “290”
      127.0.0.1:6379> zrevrangebyscore zset1 300 -inf withscores
    5. “f”
    6. “290”
    7. “g”
    8. “201”
    9. “e”
    10. “5”
    11. “d”
    12. “4”
    13. “a”
    14. “4”
    15. “c”
    16. “3”
    17. “b”
    18. “2”
      8.求指定分数范围的成员个数:zcount key min max

    9.删除指定排名内的升序元素
    zrem range by rank ey start end
    127.0.0.1:6379> zremrangebyrank zset1 0 2
    (integer) 3

    10.删除指定分数范围的成员:
    zremrangebyscore key min max
    127.0.0.1:6379> zremrangebyscore zset1 1 5
    (integer) 2

    有序集合间的操作:
    1.交集:zinterstore destination numkeys key1 key2…[weights weight] [aggregate sum|min|max]
    destination :交集结果要保存的集合名称;
    numkeys:用来求交集的集合个数;
    weights:权重,后面的weight是权重的数字,可以是多个,根据key的数量定,默认是1;
    aggregate:交集取出元素的分数可以按照sum|main|max这三种方式进行计算取值;
    zinterstore user 2 user1 user2 weights 1 0.5

    并集:zunionstore destination numkeys key1 key2…[weights weight] [aggregate sum|min|max]

    第三章 键管理与redis的一些小功能
    前面学过了type、del、object encoding 、exists、expire等
    1.键的重命名:rename key newkey
    127.0.0.1:6379> set python study
    OK
    127.0.0.1:6379> rename python java
    OK

    2.随即返回一个键:randomkey
    127.0.0.1:6379> randomkey
    “user”

    3.查看有多少个键:dbsize
    127.0.0.1:6379> dbsize
    (integer) 16

    4.键过期:expire 以秒为单位,expireat 后面跟时间戳(1970年1月1日0时0分0秒)
    127.0.0.1:6379> expireat user 1469980800
    (integer) 1

    键过期后面可以不跟时间和时间戳,而是跟ttl值来给键设置键过期
    ttl值: >0 -1 -2

    0的整数表示:键过期的时间还剩多少秒;
    -1表示:键没有设置过期时间;
    -2表示:键不存在;
    127.0.0.1:6379> EXPIRE user -2
    (integer) 0
    127.0.0.1:6379> get user
    (nil)

    1. 迁移键:
      (1)move :同一个redis的不同的库之间迁移; redis的库的索引 :0-15
      move key dbindex(库的索引)
      怎么让redis显示库的index:
      127.0.0.1:6379> set dbnumber 0
      OK
      127.0.0.1:6379> select 1
      OK
      127.0.0.1:6379[1]> select 0
      OK
      127.0.0.1:6379> get dbnumber
      “0”
      select index 这个命令用来切换库;
      127.0.0.1:6379> keys *
    1. “set1”
    2. “set3”
    3. “str”
    4. “user1_2”
    5. “java”
    6. “set2”
    7. “user1”
    8. “list2”
    9. “user2”
    10. “str1”
    11. “list”
    12. “zset1”
    13. “set”
    14. “str2”
    15. “set4”
    16. “dbnumber”
      127.0.0.1:6379> move set 15
      (integer) 1
      127.0.0.1:6379> keys *
    17. “set1”
    18. “set3”
    19. “str”
    20. “user1_2”
    21. “java”
    22. “set2”
    23. “user1”
    24. “list2”
    25. “user2”
    26. “str1”
    27. “list”
    28. “zset1”
    29. “str2”
    30. “set4”
    31. “dbnumber”
      127.0.0.1:6379> select 15
      OK
      127.0.0.1:6379[15]> keys *
    32. “set”

    (2)【dump+restore】:
    命令:
    dump key 这个在源redis上
    restore key ttl value [replace] 跟上replace表示如果目标redis上有同名key就覆盖掉
    dump key 和restore key ttl value 用于多个redis之间进行数据迁移;
    分2步:1.在源redis上,dump key 来使key序列化备份,格式rdb
    2. 在目标redis上,restore key ttl value(这个value就是序列化后的值),ttl是过期时间,
    ttl=0的时候表示永远不过期;
    127.0.0.1:6379[15]> set str1 abcdefg
    OK
    127.0.0.1:6379[15]> dump str1
    “\x00\aabcdefg\b\x00\x7f\x13\xfc\x0f\x194yf”
    127.0.0.1:6380[15]> restore str1 0 “\x00\aabcdefg\b\x00\x7f\x13\xfc\x0f\x194yf”
    OK
    127.0.0.1:6380[15]> keys *

    1. “str1”
      127.0.0.1:6380[15]> get str1
      “abcdefg”

    (3)【migrate】 多个redis之间的key迁移, redis 3.0.6版本后才有的。
    migrate相当于dump+restore+del
    migrate host port key|"" destination-db timeout [copy|replace] [keys key]
    host: 这里输入目标redis的IP
    port:输入目标redis的端口
    key|"" :指我们要迁移的键,如果要迁移的键多于1个时,我们这个位置写"",然后把这些键放在
    后面的参数keys后面;
    destination-db :目标redis的库的索引下标;
    timeout:超时时间,单位是毫秒;
    copy:表示移动key但不删除源redis上的这个key
    replace:跟上replace表示如果目标redis上有同名key就覆盖掉
    keys : 当我们要迁移多个键的时候,把这些键的其他键写在keys后边
    127.0.0.1:6379[15]> migrate 127.0.0.1 6380 str1 1 10000
    OK
    127.0.0.1:6380[15]> select 1
    OK
    127.0.0.1:6380[1]> keys *

    1. “str1”
      127.0.0.1:6380[1]> get str1
      “abcdefg”

    127.0.0.1:6379> migrate 127.0.0.1 6380 “” 1 10000 keys list2 user1
    OK
    127.0.0.1:6380[1]> keys *

    1. “str1”
    2. “list2”
    3. “user1”

    127.0.0.1:6380[1]> keys *

    1. “str1”
    2. “list2”
    3. “user1”
      127.0.0.1:6380[1]> migrate 127.0.0.1 6379 list2 1 10000 copy
      OK
      127.0.0.1:6380[1]> keys *
    4. “str1”
    5. “list2”
    6. “user1”

    历键遍
    1.keys pattern
    pattern:* 匹配任意字符;? 匹配1个字符;[]匹配方括号当中任意字符,比如[1,3]代表1,3 [1-9]匹配1到9任意数字;\x用来转义特殊字符; st\x*1

    有3种情况用到keys:
    1.不对外提供服务的redis节点;
    2.确认键值总数数量较少,可以用keys;
    用scan可以防止阻塞:
    scan:渐进式的遍历,从2.8版本才有,相当于1个keys*=多个scan
    scan cursor [match pattern] [count number]
    cursor:游标,第一次遍历一般从0开始,每次scan遍历完了都会返回当前的游标的值,然后我们再从这个游标开始遍历,知道游标值为在为0,就遍历了所有的键;
    [match pattern]:可选项,作用是做模式的匹配;
    [count number]:作用是表名每次要变遍历的个数;

    scan的缺点:不能保证完整的遍历所有键;

    关于数据库的操作:
    1.select dbindex 切换库
    2.dbsize:查看库里面有多少个键
    3.flushdb|fludhall:这个命令是清除当前库里的所有键,flushall这个是清楚所有库里的键

    1.慢查询分析:
    所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设的阈值,就将这条命令的相关信息(例如:发生时间,耗时,命令的详细信息)记录下来;
    redis的慢查询,在配置文件当中有两个配置参数:
    slowlog-log-slower-then:这个预设的阈值(单位:微妙,1秒=1000毫秒=1000000微秒)
    阈值=0,记录所有命令;阈值<0,什么都不记录;
    slowlog-max-len:慢查询日志最多存储多少条;
    若慢查询日志存满了,在有日志记录时,则删除最早一条,一次按此执行;
    慢查询命令:
    (1)slowlog get [N] N是可选项,表示我们要获取慢查询日志的条数;
    如果不为空,返回的内容应该包含以下内容:
    1)慢查询命令的时间戳;
    2)
    3)
    4)
    5)

    3.4 Redis Shell
    【Redis-cli详解】
    【-r】:代表将命令执行多次
    [root@localhost redis-4.0.2]# redis-cli -r 3 ping
    PONG
    PONG
    PONG

    【-i】:代表每隔几秒执行一次命令,但是-i 必须和-r 一起使用
    [root@localhost redis-4.0.2]# redis-cli -r 5 -i 1 ping
    PONG
    PONG
    PONG
    PONG
    PONG

    【-x】:从标准输入(stdin)读取数据作为redis-cli的最后参数
    将world作为键hello的值
    [root@localhost redis-4.0.2]# echo “world” | redis-cli -x set hello
    OK

    【-c】:该选项是连接redis cluster节点时需要使用的,-c选项可以防止moved和ask异常
    【-a】:不需要手动输入auth命令
    【–scan】用于扫描指定模式的键
    【–slave】把当前的客户端模拟当成redis节点的从节点,来获取redis节点的更新
    【–pipe】用于执行流水线,将命令封装成redis通信协议定义的数据格式,批量发送给redis执行
    【–rdb】用于拍快照(aof把快照保存在磁盘),备份,请求redis实例生成并发送RDB持久化文件,保存在本地
    【–eval】执行指定的lua脚本(与魔兽世界脚本相同)
    【–latency】查询延迟,包含以下3点
    【–latency】 该选项可以测试客户端到目标redis的网络延迟,结果只有一条
    【–latency-history】分时段的形式了解延迟信息
    【–latency-dist】 使用统计图形式从控制台输出延迟统计信息
    【–stat】选项可以实时获取redis的重要统计信息(info不是实时的)
    [root@localhost redis-4.0.2]# redis-cli --stat
    ------- data ------ --------------------- load -------------------- - child -
    keys mem clients blocked requests connections
    11 829.17K 2 0 136 (+0) 6
    11 829.17K 2 0 137 (+1) 6
    11 829.17K 2 0 138 (+1) 6
    11 829.17K 2 0 139 (+1) 6

    杜兴宇 15:08:31
    【redis-server详解】
    【–test-memory 1024】是否有内存问题造成的内存崩溃,可以用来检测当前操作系统是否稳定的分配指定容量的内存给redis
    [root@localhost src]# redis-server --test-memory 1024

    【redis-benchmark】可以为redis做基准性能测试,为开发和运维提供方便,做测试使
    【-c】代表客户端的并发量(默认50)
    【-n 】-n后面跟数量,代表客户端请求总量(默认为100 000)
    【-q】仅仅显示requests per second(请求数量,秒,等信息)信息
    【-r】在一个空的redis上执行redis-benhmark,并向redis里面插入更多随机键
    【-p】每个请求pipe流水线的数据量(默认为1)
    【-k】代表客户端是否使用keepalive,1为使用,0为没使用,默认是1

    事务:为了保证多条命令组合的原子性,redis提供了简单的事务功能以及集成脚本来解决这个问题。
    简单的说,事务表示一组动作,要么全部不执行,比如在社交网站上用户A关注用户B,那么需要在用户A的关注表中加入用户B,并且在用户B的粉丝中加入用户A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不一致的情况。
    redis事务:将一组需要一起执行的命令放到multi和exec这两个命令之间。multi命令代表事务开始exec代表事务结束;

    第四章 redis的持久化
    redis支持RDB和AOF两种持久化。持久化功能有效的避免了因为进程退出造成的数据丢失问题,
    当下次重启时利用之前持久化的文件即可实现数据恢复。
    理解持久化机制对于redis运维非常重要,
    首先我们学习RDB、AFO的配置和运行流程,以及控制持久化的相关命令,如bgsave和bgrewriteaof;其次对于常见持久化问题进行分析和优化。

    1.RDB
    RDB持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为:手动触发和自动触发。

    1.1 RDB触发机制:
    手动触发分别对应save和bgsave命令:
    手动:save和bgsave
    save:阻塞当前redis服务器,直到RDB过程完成(线上不建议使用,阻塞时间长);
    bgsave:redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动退出;
    (阻塞只发生在fork间段)

    自动:save m n
    1.表示m秒内的数据集存在n次修改时会自动触发bgsave;
    2.如果从节点执行全量复制操作,主节点自动执行bgsave,形成RDB的文件发给其他节点;
    3.执行debug reload命令重新加载redis时,也会自动触发save操作;
    4.执行shutdown时,如果AOF持久化没有开启,则自动执行bgsave。

    save命令:阻塞当前redis服务器,知道RDB过程完成,对于内存比较大的实例会造成长时间阻塞
    线上环境不建议使用。运行save命令对应的redis的日志如下:
    *DB saved on disk
    bgsave命令:redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束,阻塞只发生在fork阶段,一般时间很短。
    运行bgsave命令对应的redis日志如下:
    *background saving started by pid 3151
    *DB saved on disk
    *RDB:0MB of memory used by copy-on-write
    *background saving terminated with success

    1.2 流程说明:
    1)执行bgsave命令,redis父进程判断当前是否存在正在执行的子进程,如:RDB/AOF子进程,
    如果存在bgsave命令直接 返回。
    2)父进程执行fork操作创建进程,fork操作过程中父进程会阻塞,通过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作的耗时,单位为微秒。
    3)父进程完成fork后,bgsave命令返回’‘background saving started’’ 信息并不在阻塞父进程可以继续响应其他命令;
    4)子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件及进行原子替换。
    执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
    5)进程发送信号给父进程表示完成,父进程更新系统信息,具体在info persistence 下的rdb_*相关选项。

    1.3 RDB文件的处理
    RDB文件的保存:3种方式
    1.配置文件默认的保存路径
    2.在redis命令行 config set dbfilename ;
    3.修改配置文件redis.conf:
    dbfilename
    dir ./

    压缩:LZF默认开启:我们可以通过修改配置文件里的rdbcompression yes/no
    或者执行命令config set rdbcompression [yes/no] yes是开启压缩, no是禁用;

    1.5校验:redis-check-dump 工具对rdb可以进行检测;/user/local/redis-4.06/src下

    1.6 RDB的优缺点::
    优点:
    (1)RDB是一个紧凑压缩的二进制文件,代表redis在某个时间点上的数据快照,非常适用于备份
    全量复制等场景,比如每6小时执行bgsave备份,并把RDB文件拷贝到远程机器或者文件系统中(如hdfs),
    用于灾难恢复。
    (2)redis加载RDB恢复数据远远快于AOF的方式。
    缺点:
    (1) RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建
    子进程,属于重量级操作,频繁执行成本过高。
    (2)RDB文件使用特定二进制格式保存、redis版本演进过程中有多个格式的RDB版本,存在老版本redis服务无法
    兼容新版redis格式的问题。
    针对RDB不适合实时持久化的问题,redis提供了AOF持久化方式来解决。

    2.AOF
    开启AOF功能需要设置配置:appendonly yes,默认不开启。AOF文件名appendfilenname
    配置设置,默认文件名是appendonly.aof。保存路径和RDB持久化一直,通过dir配置指定。
    AFO的过流程操作:命令写入(append)、文件同步(sync)、文件重写(rewrite)、重启加载(load)。

    命令:
    写入:append 将执行的redis命令写入aof缓存
    aof缓冲:sync 将所有写入缓存的命令同步到磁盘
    重写:rewrite 起到压缩日志文件的目的,整理磁盘空间;
    重启:load 重启时执行AOF文件对数据进行加载;

    3.自动持久化策略:
    redis提供了多种AOF缓冲同步策略,由参数appendfsync控制,不同值得含义;
    always、everysec、no
    always:命令写入aof_buf缓存区后面调用系统fsync操作同步到AOF文件,fsync完成后线程返回(一般线上不采用always)。

    everysec: 命令写入aof_buf缓存区调用write操作,write完成后线程返回,fsync同步文件操作由
    专门的线程每秒调用一次(一般建议选择这个策略,数据性能安全的平衡);

    no:命令写入aof_buf后调用write操作,不对AOF文件做fsync同步,同步硬盘操作由系统负责,
    同步通常周期最长30秒(对线上不采用)

    注意:
    fsync针对单个文件操作,做硬盘同步,fsync将阻塞直到写入硬盘完成后返回,保证数据持久化。
    write:触发延迟写机制,write操作在写入系统缓存区之后直接返回,同步硬盘操作依赖于系统调用机制
    ,比如:缓存区页写满或达到特定时间周期,同步文件之前,如果时间系统故障宕机,缓存区内数据将丢失。

    4.重写机制(rewrite):
    随着命令不断写入AOF文件,文件会越来越大,为了解决这个问题,redis引入AOF重写机制压缩
    文件体积,AOF文件重写是把redis进程内的数据转换为命令同步到新AOF文件的过程。
    重写后的AOF文件为什么可以变小?
    (1)进程内已经超时的数据不再写入文件。
    (2)旧的AOF文件含由无效命令,如del key srem keys set a 111 set 222等。这些无效命令就不写入AOF文件里了。
    (3)多条写命令可以合并,如:lpush list a、lpush list b、lpush list c可以转化为lpush list abc。
    AOF重写降低了文件占用空间,除此之外,另一个目的是:更小的AOF文件可以更快的被redis加载。

    AOF重写过程可以手动触发,也可以自动触发:
    手动触发:直接条用bgrewiteao命令。
    自动触发:根据auto-aof-rewrite-percentage 参数确定触发器时机,auto-aof-rewrite-min-size
    表示运行AOF重写时文件最小体积,默认64MB
    auto-aof-rewrite-percentage:代表AOF文件空间(aof_current_size)和上一次重写后AOF文件空间的比值;

    问题的定位余2优化:
    1.
    1.fork操作:
    当redis做RDB或AOF
    重写时,一个必不可少的操作就是fork子进程,对于大多数操作系统来说fork是个重量级操作。
    虽然fork创建子进程不需要拷贝父进程的物理内存空间,但是需要父进程的空间存列表,例如对于10G的redis进程,
    需要复制大约20MB的内存列表,因此fork操作耗时跟进程的内存量息息相关,如果使用虚拟化技术、特别是Xen虚拟机,fork操作更耗时。
    fork耗时问题定位:对于高流量的redis实例OPS可达到5万以上,如果fork操作耗时在秒级别将拖慢redis几万条命令执行,对线上应用延迟影响非常明显,
    正常情况下fork耗时应该是每GB消耗2毫秒左右
    可以在info stats统计中查看latest_fork_user指定获取最近一次forl操作耗时,单位毫秒。

    如何改善fork操作耗时:
    (1)优先使用物理机或者高效支持fork操作的虚拟技术,避免使用Xen。
    (2)控制redis实力最大可用内存,fork耗时跟内存成正比,线上建议每个redis实例控制在10G以内。
    (3)合理配置linux内存分配策略,避免物理内存不足导致fork失败。
    (4)降低fork操作的频率,如湿度放宽AOF自动触发时机,避免不必要的全量复制。

    2.子进程开销监控和优化:
    子进程负责RDB或者AOF文件的重写,他的运行过程主要涉及到cpu、内存、硬盘三部分的消耗。
    (1)cpu开销分析,子进程负责把进程内的数据 分批写入文件,这个过程属于cpu密集操作,
    通常子进程对单核cpu利用率接近90%。
    cpu消耗的优化:redis是cpu密集型服务,不要做绑定单核cpu操作,
    子进程会和父进程产生单核资源竞争。不要和其他cpu密集服务部署在一起,造成cpu过度竞争。
    如果多个redis实例,尽量保证同一时刻只有一个子进程执行重写工作。

    2.内存消耗分析:
    子进程通过fork产生,占用内存大小等同于父进程,理论上需要两倍内存来完成持久化操作,
    但是linux系统有写时复制机制(copy-on-write)。父子进程会共享相同的内存页,当父进程处理写请求时会把要修改的内存页创建副本,而子进程fork操作过程中共享整个
    父进程内存页快照。

    3.硬盘的开销分析:
    子进程主要职责就是把AOF或者RDB文件写入硬盘持久性,势必造成硬盘写入压力。
    根据redis重写AOF/RDB的数量,结合系统工具如sar、iostat、iotop等,
    可分析重重写期间负载情况。

    硬盘开销优化:
    (1)不要和其他高硬盘的服务部署到一起。
    (2)AOF重写时会消耗大量硬盘IO,可以开启配置no-appendfsync-no-rewrite,默认关闭,表示在AOF重写期间不做fsync操作/
    (3)当开启AOF功能的redis用于高流量写入场景时,如果使用普通机械硬盘,写入吐量一般在100MB/s左右,这是redis实例的瓶颈
    主要在AOF同步硬盘上。
    (4)对于单机配置多个redis实例情况,可以配置不同实例分盘写入压力。

    第五章 redis的复制
    为了解决redis单节点的问题,为了保证数据的安全性,通常会把数据复制多个副本部署到其他服务器上,满足故障恢复和负载均衡的需求。
    redis我们提供复制功能,它的复制方式主要有两种:1,主从复制 2.从从复制。

    1.建立配置:
    参与复制的redis实例划分主节点(master)和从节点(slave)。默认情况下,redis都是主节点,每一个从节点他只能有一个主节点,
    而主节点可以同时具有多个从节点,复制的数据流是单向的。
    配置复制的方式有以下三种:
    (1)在从节点的配置文件中加入:slaveof(master) (masterport)随着redis启动生效
    (2)在redis-server启动命令后加上–slaveof (master) (masterport)生效;
    (3)在redis命令行直接执行命令:slaveof (master) (masterport)生效;

    我们可以通过命令:info replication 可以在主节点或者从节点上查看主从信息

    2.断开主从复制:
    slaveof命令不但可以建立复制,还可以在从节点上执行saveof no one断开与主节点复制关系。
    断开复制主要流程:
    (1)断开主节点复制关系;
    (2)从节点晋升为主节点;

    从节点断开复制后并不会抛弃原有数据,只是无法在获取
    主节点上的数据变化,
    通过slaveof命令还可以切主,切主就是把当前从节点的复制,切换到另一台主节点上的复制。命令:
    slaveof 新主节点的ip 新节点的port 即可完成切主。

    3设置.主从复制的安全配置:
    对于数据比较重要的节点,主节点会通过requirepass参数进行密码验证,这时所有的客户端访问
    必须用auth命令实行校验,从节点与主节点的复制链接是通过一个特殊标识的客户端来完成的,
    因此需要配置从节点的requirepass参数与主节点密码一致,这从节点才可以正确的

    4.只读
    默认情况下,从节点使用siave-read-only=yes配置为只读,由于复制只能从主节点到从节点,对于从节点
    的任何修改主节点无法感知,修改从节点会造成主从数据不一致。因此建议线上不要修改从节点
    的只读模式。

    5.传输延迟:
    主从节点一般部署在不同机器上,复制时的网络延迟就成为需要考虑的问题,redis为我们提供了repl-disable-tcp-nodelay参数用于控制是否
    关闭TCP_NODELAY,默认
    关闭,说明如下:
    (1)当关闭时,主节点产生 的命令数据无论大小都会及时地发送给从节点,这样主从节点之间延迟会变小,但增加了网络带宽的消耗,适用于主从之间的网络环境良好的场景,比如在同一个机房内的服务器。
    (2)当开启时,主节点会合并较小的TCP数据包从而节省带宽,默认发送时间间隔取决于linux的内核,一般默认40毫秒,这种配置节省了带宽增大了主从之间的延迟,适合于主从网络环境复杂或带宽警长的场景,如机房部署。

    6.主从拓扑:
    1.主从,2.树状主从结构;

    7.复制过程的原理:
    (1)slave向master发送sync命令
    (2)master开启了进程来将dataset写入rdb文件,同时将子进程完成之前接收到的命令缓存起来。
    (3)子进程写完,父进程得知,开始将RDB文件发送给slave。
    (4)master发送完RDB文件,将缓存的命令也发给slave。
    (5)master增量的把命令发送给slave。
    值得注意的是,当slave跟master的链接断开时,slave可以自动的重新连接master,在redis2.8版本之前,每当slave进程挂掉重新连接master

    7.心跳
    朱从几点在建立复制后,他们之间维护者连接并彼此发送心跳命令,主从心跳判断机制:
    (1)主从点彼此都有心跳检测机制,各自模拟成对方的客户端通信,通过client list命令查看复制相关的哭护信息,主节点的连接状态为flags:M,从节点的连接状态为flags:S
    (2)主节点默认每隔10秒发送给从节点ping命令,判断从节点的存活和连接状态,可以通过repl-ping-slave-period 10 设置多少秒发送ping命令;
    (3)从节点在主线程中每个1秒发送replconf ack {offset}给主节点上报自身当前的复制偏移量。
    replconf作用
    (1)实时检测主节点网络状态;
    (2)上报自身复制偏移量,检测复制数据是否丢失,如果从节点数据丢失,在从主节点的积压复制缓存区里拉取丢失的数据;
    (3)时间保证从节点的数量和延迟性功能,通过min-slaves-to-write、min-salves-max-lag参数定义。主节点根据repconf命令判断从节点超时时间,体现在info replication统计中的lag信息中lag表示与从节点最后一次通信延迟的秒数,正常延迟应该在0-1之间,如果超过了repl-timeout配置值(默认60秒),则判定从节点下线并且断开复制客户端连接。即使主节点判定从节点下线后如果从节点重新恢复,心跳检测会继续进行。

    8.异步复制
    主节点不断负责数据的读写,还负责把命令同步给从节点。写命令的发送过程时异步的,也就是说主节点自身处理完命令后直接返回给客户端,并不等从节点复制完成。
    主节点复制的流程:
    (1)主节点接受写命令‘
    (2)命令执行完之后返回给客户端执行结果;
    (3)异步写命令发送给从节点;
    由于主从复制是异步的,就会造成从节点的数据相对于主节点在延迟,具体延迟多少字节。我们可以在主节点上执行info replication命令相关指标:offset和master_repl_offset之间的差值就是延迟的字节;

    在统计信息中可以看到从节点slave0信息,分别记录了从节点的ip、port、状态、offset表示当前从节点的复制偏移量,master_repl_offset表示当前主节点复制偏移量,两者的差值就是延迟量。
    redis的复制速度取决于主从之间的网络环境,repo-disable-tcp-nodelay,命令处理速度等。正常情况下,延迟在1秒以内。

    9.开发与运维中的问题
    理解了复制原理之后,我们来看一些容易出现问题的应用场景:
    1.读写分离的问题:
    master负责写,slave负责遇到的问题:
    (1)复制数据延迟;(2)读到过期的数据;(3)从节点故障
    1.复制数据延迟:
    redis复制数据的延迟由于异步复制特性是无法避免的,延迟取决于网络带宽和命令阻塞 情况,比如刚在主节点写入数据后立刻在从节点上读取可能获取不到,需要业务场景允许短时间内的数据延迟对于无法容忍大量延迟的场景,可以编写外部监控程序监听主从节点的复制偏移量,
    当延迟较大时,触发报警或者通知客户端避免读取过高的从节点。
    监控程序:定期检查主从节点的偏移量,主从节点偏移量的差值叫做主从节点延迟的字节,当延迟过高时,监控程序触发报警,并通知客户端从节点延迟过高,客户端接收到具体的从节点读命令请求。

    2.读到过期数据的问题:
    当主节点存储大量设置超时间数据时,如缓存数据,redis内部需要维护过期数据删除策略,
    删除策略主要有两种:
    一种叫惰性删除,另一种叫做定时删除
    惰性删除,主节点每次处理读取命令时,都会检查键是否超时,如果超时,则执行del删除键,del命令异步发送给从节点,从节点永远不会主动删除超时的数据;
    定时删除,redis主节点在内部时任务会循环采样一定数量的键,当发现采样的键过期时执行del命令之后在同步给从节点。
    如果此时数据大量超时,主节点采样速度跟不上过期且主节点没有读取过期键的操作,那么从节点将无法收到del命令。这时在从节点上可以读取到已经超时的数据,redis在3.2版本解决了这个问题,从节点读取数据之前会键的过期时间决定是否返回数据,可以升级到3.2版本来规避这个问题。

    3.从节点故障问题:
    对于从节点的故障问题,需要在哭护端维护,维护可用的节点列表,当从节点故障时,会立刻切换到其他的从节点或主节点上,由监控程序完成。

    2.主从配置不一致:
    主从配置不一致是一个容易忽视的问题,对于有些配置主从之间是可以不一致的,比如:主节点关闭AOF但是从节点开启。但对于内存相关的配置必须一致,比如:maxmemory,
    hash-max-ziplist-entries等参数。
    当配置的maxmeory-policy策略进行内存溢出控制,此时从节点数据已经丢失,但主从复制流程依然正常进行,复制偏移量也正常,当增大了从节点的内存,要修复这类问题也只能手动进行全量复制。当压缩列表相关参数不一致时,虽然主从节点存储的数据一致,但是时间占用情况差异会比较大。

    4.规避全量复制:
    第一次建立连接的复制:由于是第一次建立复制,从节点不包含任何主节点数据,因此必须进行全量复制才能完成数据同步。对于这种情况全量制无法避免。当对数据量较大却流量较高的主节点添加从节点时,建议在低峰进行操作,或者尽量规避使用大量的redis节点。
    节点运行id不匹配:当主从复制关系建立后,从节点会保存主节点的运行id,如果此时主节点因故障重启,那么他的运行id会变,从节点发现主节点的运行id不匹配时,会认为自己复制的是一个新主节点,从而进行全量复制,对于这种情况应该从架构上规避,比如提供故障转移功能,当主节点发生故障后,手动提升一个从节点为主节点或采用支持自动故障转移的哨兵或集群方案。
    (3)复制积压缓存区不足:当主从节点连接中断后,从节点在次连接上主节点时会发送psync(runid)(offset),命令请求增量复制,但是请求的offset不在主节点的积压缓存区内,则无法提供给从字节点数据,因此增量复制会退化为全量复制,针对这种情况需要根据网络中断时长,调整复制积压缓存的大小。
    入数据量,调整复制积压缓存区的大小。
    网络中断一般有闪断、机房割接、网络分区等情况,这时网络中断的时长一般在分钟级,写命令可以查看的差值来计算出网络中断大约产生多少新写入的数据来修改缓存区大小。因而可以避免由于复制积压缓存区不足造成的全量复制。

    5.单节点复制风暴:
    单节点复制风暴一般发生在主节点挂载多个从节点的场景。当主节点重启恢复后,从节点会发起全量复制流程,这时主节点创建RDB快照,如果在快照创建完毕之前,有多个从节点都尝试与主节点进行全量同步,那么其他从节点将共享这份RDB快照。这点redis做了优化,有效避免了创建多个RDB快照,但是,,同时向多个从节点发送RDB快照,可能使主节点的网络带宽消耗严重,造成主节点的延迟变大,极端情况会发生主从节点连接断开,导致复制失败。
    解决方案:首先可以也减少主节点挂载从节点的数量,或者采用树状复制结构,加入中间层从节点用来保护主节点。从节点采用树状复制非常有用,网络开销交给位于中间层的从节点,而不必消耗主节点的网络带宽,但是这种树状结构带来了运维的复杂性增加了手动和自动处理故障转移的难度。

    单机复制风暴
    由于redis的单线程架构,通常单带机器会部署多个redis实例,但一台机器同时部署多个主节点,如果这台机器出项故障或者网络长时间中断
    ,当他重启恢复后,会有大量从节点针对这台机器的主节点进行全量复制,会造成当前机器网络带宽耗尽。
    如何避免?方法如下:
    (1)应该尽量避免多台主节点部署在同一台服务器上,尽量分散部署。
    (2)当主节点所在机器

    redis的哨兵(sentinel):
    redis的主从复制模式下,一旦主节点由于故障不能提供服务,需要人工将从节点晋升为主节点。
    同时要通知应用方更新新节点地址,对于很多场景故障处理的方式是无法接受的。可服务,喜的是2.8版本开始提供了redis sentinel(哨兵)架构来解决这个问题。

    1.redis主从复制问题:
    redis主从复制模式可以将主节点的数据改变同步给从节点,这样呢从节点就可以起到2个作用:
    第一,作为主节点的一个备份,一旦主节点出了故障从节点 可以作为后备’‘顶上来’'提供服务,并且保证了数据的安全性;第二,从节点可以扩展主节点读的能力,一旦主节点不能支撑大并发量的读操作,从节点可以在一定程度上帮助主节点分担读的压力。
    但是主从复制也带了以下问题:
    (1)一旦主节点出现故障,需要手动将一个从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要 命令其他从节点去复制新的主节点,整个过程需要人为操作,同时耗时较长。
    (2)主节点的写能力受到单机的限制。
    (3)主节点的存储能力受到单机的限制。
    哨兵主要解决第一个问题。

    高可用
    redis主从复制模式下,一旦主出现故障,需要人工故障转移,无论对redis的应用还是运维方都带来很大的不便,对于应用方来说无法及时感知到主节点的变化,必然会造成一定的写数据丢失和读数据的错误,甚至可能造成应用方服务不可用,对于redis的运维来说,整个故障转移的过程是需要人工来介入的,故障转移实时性和准确性都无法得到保障。
    一个1主2从的redis主从复制模式下的主节点故障了,是如何进行故障转移的?
    (1)主节点发生故障后,客户端连接到主节点失败,两个从节点与主节点的连接失败造成复制中断。
    (2)如果主节点无法正常启动,需要选出一个从节点(slave1),对其执行slave no one命令使其成为新的主节点。
    (3)原来的从节点(slave1)成为新的主节点后,更新应用方的主节点信息,从新启动应用方。
    (4)客户端命令另外一个从节点(slave2)去复制新的主节点。
    (5)待原来的主节点恢复后,让他去复制新的主节点。

    哨兵部署安装:
    在安装目录下有sentinel.conf这个哨兵的配置文件,我们修改这个配置文件部署sentinel:
    sentinel monitor mastername masterip masterport quorum(这里填数字)
    sentinel monitor mymaster 192.168.1.1 6379
    这个选项指定了我们哨兵要监控的主节点,一个哨兵可以同时监控多个主节点(多个redis集群);
    我我们只需要增加以上配置就可以了。
    2.sentinel down-after-milliseconds mastername 30000(默认值)
    这一项配置是指定主节点多少毫秒没有回应就认为主节点下线了;
    3.sentinel parallel-syncs mastername 1(默认值)
    这一项是设置故障转移后,同时可以有几个从节点对主节点数据进行复制;
    4.sentinel failover-timeout mastername 180000(默认)
    这一项是故障转移的超过了设置故障转移失败,下一次故障转移的超时间会变成这个设置时间的两倍;

    failover-time 这个超时间主要体现现在4个阶段:
    (1)如果redis sentinel对一个主节点故障转移失败,那么下次在对该主节点做故障转移的超时时间就会是failover-timeout的2倍;
    (2)如果sentinel节点选出的从节点执行slaveof no one一直失败(例如该从节点此时出现故障)当过程超过了failover-timeout,则故障转移失败;
    (3)从节点晋升为主节点之后,sentinel节点还会发送info命令来确认主节点故障转移成功,如果此过程执行时间超过了failover-timeout,则故障转移失败。
    (4)从节点连接新的主节点超时,故障转移失败 ;这个failover-timeout不包含主从复制的过程;

    4.sentinel auth-pass
    如果我么要监控的主节点设置了密码,那么我们就通过这一项来填写主节点的名称和密码,以确保能够监控到主节点;

    5.sentinel notification-script
    在故障转移期间,当一些警告级的sentine时间发生(指重要事件,例如:-sdown:客观下线、-odown:主管下线)时,会触发对路径的脚本,并向脚本发送相应的事件参数。

    6.sentinel client-reconfig-script
    他的作用是在故障转移结束后,会触发对应路径的脚本,并向脚本发送故障结果的相关参数。

    启动sentinel节点的方法:
    第一种:redis-server redis-sentinel.conf
    第二种:redis-server redis-sentinel.conf -sentinel
    登录sentinel节点客户端命令:redis-cli -p 26379(默认)

    sentinel节点不是数据点,所以它支持的命令不多,主要有以下常用:
    1.sentinel master 展示所有被监视的主节点状态以及相关的信息;
    2.sentinel slaves
    展示所有指定的master的从节点的状态及相关的统计信息:
    3.sentinel master
    展示指定的主节点的详细信息;
    4.sentinel sentinel
    展示指定的主节点的哨兵的相关信息;
    5.sentinel get-master-addr-by-name
    返回指定master的ip地址和端口;
    6.sentinel reset
    当前sentinel节点对符合(通配符风格)的主节点的配置进行重置,包括清除主节点的相关状态(例如故障转移),从新发现从节点和sentinel节点。
    对指定的master强制故障转移(没有和其他sentinel节点协商),当故障转移完成后,其他的sentinel节点按照故障的结果更新自身配置;

    8.sentinel ckquorum
    检测当前主节点的哨兵是否到达quorum的个数,ckquorum填的数和quorum对比;
    9.将sentinel节点的配置信息强制写到磁盘上;
    10.sentinel remove
    取消当前sentinel节点对于指定主节点的控制;
    11.sentinel monitor
    指定监控的主节点name、ip、port、quorum
    12.sentinel set
    动态修改sentinel节点配置选项
    13.sentinel is-master-down-by-addr
    sentinel节点之间用来交换对主节点是否下线的判断,根据参数不同,还可以作为sentinellingdaozhe选举的通信方式;

    部署技巧
    到现在有关Redis Sentinel的配置和部署方法相信你们已经基本掌握了,但在实际生产环境中都有哪些部署的技巧?本节将总结一下。

    1. Sentinel节点不应该部署在一台物理“机器”上。
      这里特意强调物理机是因为一台物理机做成了若干虚拟机或者现今比较流行的容器,它们虽然有不同的IP地址,但实际上它们都是同一台物理视,同一台物理机意味着如果过台机器有什么硬件故障,所有的虚拟机都会受到影响,为了实现Sentinel节点集合真正的高可用,请勿将Sentinel节点部署在同一台物理机器上。
      2)部署至少三个且奇数个的sentinel点。
      3个以上是通过增加Sentinel节点的个数提高对于故障判定的准确性,因为领导者选举需要至少一半加1个节点,奇数个节点可以在满足该条件的基础上节省一个节点。
      3)只有一套Sentinel,还是每个主节点配置一套Sentinel?
      Sentinel节点集合可以只监控一个主节点,也可以监控多个主节点那么在实际生产环境中更偏向于哪一种部署方式呢,下面分别分析两种方案的优缺点。
      方案一:一套Sentinel,很明显这种方案在一定程度上降低了维护成本,因为只需要维护固定个数的Sentinel节点,集中对多个Redis数据节点进行管理就可以了。但是这同时也是它的缺点,如果这套Sentinel节点集合出现异常,可能会对多个Redis数据节点造成影响。还有如果监控的Redis数据节点较多,会造成Sentinel节点产生过多的网络连接,也会有一定的影响。
      方案二:多套Sentinel,显然这种方案的优点和缺点和上面是相反的,每个Redis主节点都有自己的Sentinel节点集合,会造成资源浪费。但是优点也很明显,每套Redis Sentinel都是彼此隔离的。

    6.4 实现原理
    本节将介绍Redis Sentinel的基本实现原理,具体包含以下几个方面: Redis Sentinel的三个定时任务、主观下线和客观下线、Sentinel领导者选举、故障转移,相信通过本节的学习同学们能对Redis Sentinel的高可用特性有更加深人的理解和认识。

    6.4.1 三个定时监控任务
    一套合理的监控机制是Sentinel节点判定节点不可达的重要保证, Redis Sentinel通过三时监控任务完成对各个节点发现和监控:
    1)每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新的拓扑结构。

    这个定时任务的作用具体可以表现在三个方面:
    (1)通过向主节点执行info命令,获取从节点的信息,这也是为什么Sentinel节点不需要显式配置监控从节点。
    (2)当有新的从节点加入时都可以立刻感知出来。
    (3)节点不可达或者故障转移后,可以通过into命令实时更新节点拓扑信息。

    2)每隔2秒,每个Sentinel节点会向Redis数据节点的_sentinel :hello频道上发送该Sentinel节点对于主节点的判断以及当前Sentinel节点的信息,同时每个Sentinel节点也会订阅该频道,来了解其他Sentinel节点以及它们对主节点的判断,所以这个定时任务可以完成以下两个工作:
    (1)发现新的Sentinel节点:通过订阅主节点的_sentinel
    :hello了解其他的Sentinel节点信息,如果是新加人的Sentinel节点,将该Sentinel节点信息保存起来,并与该Sentinel节点创建连接。
    (2)Sentinel节点之间交换主节点的状态,作为后面客观下线以及领导者选举的依据。
    Sentinel节点publish的消息格式如下:
    <Sentinel 节点IP> <Sentinel 节点端口> <Sentinel 节点runId > <Sentinel 节点配置版本> <主节点名字> <主节点IP> <主节点端口> <主节点配置版本>

    1. 每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点发送一条ping命令做一次心跳检测,来确认这些节点当前是否可达。通过上面的定时任务, Sentinel节点对主节点、从节点、其余Sentinel节点都建立起连接,实现了对每个节点的监控,这个定时任务是节点失败判定的重要依据。

    6.4.2 主观下线和客观下线
    1、主观下线
    刚才介绍的第三个定时任务,每个Sentinel节点会每隔1秒对主节点、从节点、其他Sentinel节点发送ping命令做心跳检测,当这些节点超过down-after-milliseconds没有进行有效回复, Sentinel节点就会对该节点做失败判定,这个行为叫做主观下线。从字面意思也可以很容易看出来主观下线是当前sentinel节点的一家之言,存在误判的可能。

    2、客观下线
    当Sentinel主观下线的节点是主节点时,该Sentinel节点会通过sentinel is-master-down-by-addr命令向其他Sentinel节点询问对主节点的判断,当超过个数,
    Sentinel节点认为主节点确实有问题,这时该Sentinel节点会做出客观下线的决定,这样客观下
    线的含义是比较明显了,也就是大部分Sentinel节点都对主节点的下线做了同意的判定,那么
    这个判定就是客观的。
    Sentinel is-master-down-by-addr <current_epoch>
    Ip:主节点IP
    Port:主节点端口
    Current_epoch:当前配置时间
    Runid:不同类型决定了次API作用的不同
    当runid等于“*”时,作用是Sentinel节点直接交换对主节点下线的判定。
    当runid等于当前Sentinel节点的runid时,作用是当前Sentinel节点希望目标Sentinel节点同意自己成为领导者的请求。

    6.4.3 领导者sentinel节点选举
    假如Sentinel节点对于主节点已经做了客观下线,那么是不是就可以立即进行故障转移了?当然不是,实际上故障转移的工作只需要一个Sentinel节点来完成即可,所以Sentinel节点之间会做一个领导者选举的工作,选出一个Sentinel节点作为领导者进行故障转移的工作。Redis使用了Raft算法实现领导者选举,因为Raft算法相对比较抽象和复杂,以及篇幅所限,所以这里给出一个Redis Sentinel进行领导者选举的大致思路:
    1)每个在线的Sentinel节点都有资格成为领导者,当它确认主节点主观下线时候,会向其他Sentinel节点发送sentinel is-master-down-by-addr命令,要求将自己设置为领导者。
    2)收到命令的Sentinel节点,如果没有同意过其他Sentinel节点的sentinel is-master-down-by-addr命令,将同意该请求,否则拒绝。
    3)如果该Sentinel节点发现自己的票数已经大于等于max (quorum, num (sentinels)/2+1),那么它将成为领导。
    4)如果此过程没有选举出领导者,将进入下一次选举。

    实际上Redis Sentinel实现会更简单一些,因为一旦有一个Sentinel节点获得了max (quorum,num (sentinels)/2 + 1)的票数,其他Sentinel节点再去确认已经没有意义了,因为每个sentinel节点只有一票。

    6.4.4 故障转移
    领导者选举出的Sentinel节点负责故障转移,具体步骤如下:
    1)在从节点列表中选出一个节点作为新的主节点,选择方法如下:
    a)过滤: “不健康”(主观下线、断线)、5秒内没有回复过Sentinel节点ping响应、与主节点失联超过down-after-milliseconds*10秒。
    b)选择slave-priority (从节点优先级)最高的从节点列表,如果存在则返回,不存在则继续。
    c)选择复制偏移量最大的从节点(复制的最完整),如果存在则返回,不存在则继续。
    d)选择runid最小的从节点。

    1. Sentinel领导者节点会对第一步选出来的从节点执行slaveof no one命令让其成为主节点。
    2. Sentinel领导者节点会向剩余的从节点发送命令,让它们成为新主节点的从节点,复制规则和parallel-syncs参数有关。
      4)sentinel节点集合会将原来的主节点更新为从节点,并保持着对其关注,当其恢复后命令它去复制新的主节点。

    6.5 节点运维
    1.节点下线
    在介绍如何进行节点下线之前,首先需要明白两个概念:临时下线和永久下线。
    临时下线:暂时将节点关掉,之后还会重新启动,继续提供服务。
    永久下线:将节点关掉后不再使用,需要做一些清理工作,如删除配置文件、持久化文件、日志文件。
    所以你需要并清楚本次下线操作是临时下线还是永久下线。通常来看,无论是主节点、从节点还是Sentinel节点,下线原因无外乎以下几种:
    1、节点所在的机器出现了不稳定或者即将过保被收回
    2、节点所在的机器性能比较差或者内存比较小,无法支撑应用方的需求
    3、节点自身出现服务不正常情况,需要快速处理

    (1)主节点
    如果需要对主节点进行下线,比较合理的做法是选出一个“合适"(例如性能更高的机器)
    的从节点,使用sentinel failover功能将从节点晋升主节点, sentinel failover

    (2)从节点和sentinel
    如果需要对从节点或者Sentinel节点进行下线,只需要确定好是临时还是永久下线后执
    行相应操作即可。如果使用了读写分离,下线从节点需要保证应用方可以感知从节点的下线变化,从而把读取请求路由到其他节点。
    需要注意的是, Sentinel节点依然会对这些下线节点进行定期监控,这是由Redis sentinel的设计思路所决定。

    2、节点上线
    (1)添加从节点
    添加从节点的场景大致有如下几种:

    1. 使用了读写分离,但现有的从节点无法支撑应用方的流量。
    2. 主节点没有可用的从节点,无法支持故障转移。
    3. 添加一个更强悍的从节点利用手动failover替换主节点。
      添加方法:添加slaveof (masterIp) (masterPort)的配置,使用redis-server启动即可,它将被Sentinel节点自动发现。

    (2)添加sentinel节点
    添加Sentinel节点的场景可以分为以下几种:
    1)当前Sentinel节点数量不够,无法达到Redis Sentinel健壮性要求或者无法达到票数。
    2)原Sentinel节点所在机器需要下线。
    添加方法:添加sentinel monitor主节点的配置,使用redis-sentinel启动即可,它将被其余Sentinel节点自动发现。

    (3)添加主节点
    因为Redis Sentinel中只能有一个主节点,所以不需要添加主节点,如果需要替换主节点,可以使用Sentinel failover手动故障转移。

    3、节点配置
    有关Redis数据节点和Sentinel节点配置修改以及优化的方法,前面的章节已经介绍过
    了,这里给出Sentinel节点配置时要注意的地方:
    (1)Sentinel节点配置尽可能一致,这样在判断节点故障时会更加准确。
    (2)Sentinel节点支持的命令非常有限,例如config命令是不支持的,而Sentinel节点也需要dir、loglevel之类的配置,所以尽量在一开始规划好,不过所幸Sentinel节点不存储数据,如果需要修改配置,重新启动即可。

    展开全文
  • 数据库分区、分表、分、分片

    万次阅读 多人点赞 2018-06-05 09:45:13
    一、分区的概念 数据分区是一种物理数据库的设计技术,它的目的...另外,分区可以做到将表的数据均衡到不同的地方,提高数据检索的效率,降低数据库的频繁IO压力值,分区的优点如下:1、相对于单个文件系统或是硬盘...

    一、分区的概念

            数据分区是一种物理数据库的设计技术,它的目的是为了在特定的SQL操作中减少数据读写的总量以缩减响应时间。

            分区并不是生成新的数据表,而是将表的数据均衡分摊到不同的硬盘,系统或是不同服务器存储介子中,实际上还是一张表。另外,分区可以做到将表的数据均衡到不同的地方,提高数据检索的效率,降低数据库的频繁IO压力值,分区的优点如下:

    1、相对于单个文件系统或是硬盘,分区可以存储更多的数据;

    2、数据管理比较方便,比如要清理或废弃某年的数据,就可以直接删除该日期的分区数据即可;

    3、精准定位分区查询数据,不需要全表扫描查询,大大提高数据检索效率;

    4、可跨多个分区磁盘查询,来提高查询的吞吐量;

    5、在涉及聚合函数查询时,可以很容易进行数据的合并;

    二、分类 (row 行 ,column 列

    1、水平分区

    这种形式分区是对表的行进行分区,通过这样的方式不同分组里面的物理列分割的数据集得以组合,从而进行个体分割(单分区)或集体分割(1个或多个分区)。所有在表中定义的列在每个数据集中都能找到,所以表的特性依然得以保持。
    举个简单例子:一个包含十年发票记录的表可以被分区为十个不同的分区,每个分区包含的是其中一年的记录。(朋奕注:这里具体使用的分区方式我们后面再说,可以先说一点,一定要通过某个属性列来分割,譬如这里使用的列就是年份)

    2、垂直分区

    这种分区方式一般来说是通过对表的垂直划分来减少目标表的宽度,使某些特定的列被划分到特定的分区,每个分区都包含了其中的列所对应的行。
    举个简单例子:一个包含了大text和BLOB列的表,这些text和BLOB列又不经常被访问,这时候就要把这些不经常使用的text和BLOB了划分到另一个分区,在保证它们数据相关性的同时还能提高访问速度。
    在数据库供应商开始在他们的数据库引擎中建立分区(主要是水平分区)时,DBA和建模者必须设计好表的物理分区结构,不要保存冗余的数据(不同表中同时都包含父表中的数据)或相互联结成一个逻辑父对象(通常是视图)。这种做法会使水平分区的大部分功能失效,有时候也会对垂直分区产生影响。

    三、分区、分表、分库的详细理解

    一、什么是分区、分表、分库

    分区

    就是把一张表的数据分成N个区块,在逻辑上看最终只是一张表,但底层是由N个物理区块组成的

    分表

    就是把一张表按一定的规则分解成N个具有独立存储空间的实体表。系统读写时需要根据定义好的规则得到对应的字表明,然后操作它。

    分库

    一旦分表,一个库中的表会越来越多

    将整个数据库比作图书馆,一张表就是一本书。当要在一本书中查找某项内容时,如果不分章节,查找的效率将会下降。而同理,在数据库中就是分区

    二、常用的单机数据库的瓶颈

    问题描述

    • 单个数据量越大,读写锁,插入操作重新建立索引效率越低。
    • 单个数据量太大(一个数据库数据量到1T-2T就是极限)
    • 单个数据库服务器压力过大
    • 读写速度遇到瓶颈(并发量几百)

    三、分区

    什么时候考虑使用分区?

    • 一张表的查询速度已经慢到影响使用的时候。

    • sql经过优化

    • 数据量大

    • 表中的数据是分段的
    • 对数据的操作往往只涉及一部分数据,而不是所有的数据

    分区解决的问题

    主要可以提升查询效率

    分区的实现方式(简单)

    mysql5 开始支持分区功能

    CREATE TABLE sales (
        id INT AUTO_INCREMENT,
        amount DOUBLE NOT NULL,
        order_day DATETIME NOT NULL,
        PRIMARY KEY(id, order_day)
    ) ENGINE=Innodb 
    PARTITION BY RANGE(YEAR(order_day)) (
        PARTITION p_2010 VALUES LESS THAN (2010),
        PARTITION p_2011 VALUES LESS THAN (2011),
        PARTITION p_2012 VALUES LESS THAN (2012),
    PARTITION p_catchall VALUES LESS THAN MAXVALUE);

    四、分表

    什么时候考虑分表?

    • 一张表的查询速度已经慢到影响使用的时候。

    • sql经过优化

    • 数据量大
    • 当频繁插入或者联合查询时,速度变慢

    分表解决的问题

    分表后,单表的并发能力提高了,磁盘I/O性能也提高了,写操作效率提高了

    • 查询一次的时间短了
    • 数据分布在不同的文件,磁盘I/O性能提高
    • 读写锁影响的数据量变小
    • 插入数据库需要重新建立索引的数据减少

    分表的实现方式(复杂)

    需要业务系统配合迁移升级,工作量较大

    分区和分表的区别与联系

    • 分区和分表的目的都是减少数据库的负担,提高表的增删改查效率。

    • 分区只是一张表中的数据的存储位置发生改变,分表是将一张表分成多张表。
    • 当访问量大,且表数据比较大时,两种方式可以互相配合使用。
    • 当访问量不大,但表数据比较多时,可以只进行分区。

    常见分区分表的规则策略(类似)

    1. Range(范围)
    2. Hash(哈希)
    3. 按照时间拆分
    4. Hash之后按照分表个数取模
    5. 在认证库中保存数据库配置,就是建立一个DB,这个DB单独保存user_id到DB的映射关系

    12306的订单是如何存储的?

    五、分库

    什么时候考虑使用分库?

    • 单台DB的存储空间不够
    • 随着查询量的增加单台数据库服务器已经没办法支撑

    分库解决的问题

    其主要目的是为突破单节点数据库服务器的 I/O 能力限制,解决数据库扩展性问题。 

    垂直拆分

    将系统中不存在关联关系或者需要join的表可以放在不同的数据库不同的服务器中。

    按照业务垂直划分。比如:可以按照业务分为资金、会员、订单三个数据库。

    需要解决的问题:跨数据库的事务、jion查询等问题。

    水平拆分

    例如,大部分的站点。数据都是和用户有关,那么可以根据用户,将数据按照用户水平拆分。

    按照规则划分,一般水平分库是在垂直分库之后的。比如每天处理的订单数量是海量的,可以按照一定的规则水平划分。需要解决的问题:数据路由、组装。

    读写分离

    对于时效性不高的数据,可以通过读写分离缓解数据库压力。需要解决的问题:在业务上区分哪些业务上是允许一定时间延迟的,以及数据同步问题。

    思路

    垂直分库-->水平分库-->读写分离

    六、拆分之后面临新的问题

    问题

    • 事务的支持,分库分表,就变成了分布式事务
    • join时跨库,跨表的问题
    • 分库分表,读写分离使用了分布式,分布式为了保证强一致性,必然带来延迟,导致性能降低,系统的复杂度变高。

    常用的解决方案:

    对于不同的方式之间没有严格的界限,特点不同,侧重点不同。需要根据实际情况,结合每种方式的特点来进行处理。

    选用第三方的数据库中间件(Atlas,Mycat,TDDL,DRDS),同时业务系统需要配合数据存储的升级。

    七、数据存储的演进

    单库单表

    单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到。

    单库多表

    随着用户数量的增加,user表的数据量会越来越大,当数据量达到一定程度的时候对user表的查询会渐渐的变慢,从而影响整个DB的性能。如果使用mysql, 还有一个更严重的问题是,当需要添加一列的时候,mysql会锁表,期间所有的读写操作只能等待。

    可以通过某种方式将user进行水平的切分,产生两个表结构完全一样的user_0000,user_0001等表,user_0000 + user_0001 + …的数据刚好是一份完整的数据。

    多库多表

    随着数据量增加也许单台DB的存储空间不够,随着查询量的增加单台数据库服务器已经没办法支撑。这个时候可以再对数据库进行水平拆分。

    八、总结

    总的来说,优先考虑分区。当分区不能满足需求时,开始考虑分表,合理的分表对效率的提升会优于分区。

    九、案例分析

    京东的商品评价存储设计,原文地址

    现状

    • 商品的评论数量:数十亿条
    • 每天的服务调用:数十亿次
    • 每年成倍增长

    整体的数据存储:基础数据存储,文本存储

    img

    基础数据存储

    Mysql:只存储非文本的基础信息。包括:评论状态,用户,时间等基础数据。以及图片,标签,点赞等附加信息。数据组织形式(不同的数据又可选择不同的库表拆分方案):

    • 评论基础数据按用户ID进行拆库并拆表
    • 图片及标签处于同一数据库下,根据商品编号分别进行拆表
    • 其它的扩展信息数据,因数据量不大、访问量不高,处理于同一库下且不做分表即可

    文本存储

    文本存储(评论的内容)使用了mongodb、hbase

    • 选择nosql而非mysql
    • 减轻了mysql存储压力,释放msyql,庞大的存储也有了可靠的保障
    • nosql的高性能读写大大提升了系统的吞吐量并降低了延迟


    转自:http://www.cnblogs.com/bluebluesky/articles/6413831.html

    作者:bluebluesky

    也可参考:https://blog.csdn.net/kingcat666/article/details/78324678

    里面会有详细的说明!!我就不转载了!!


    数据分片

    在分布式存储系统中,数据需要分散存储在多台设备上,数据分片(Sharding)就是用来确定数据在多台存储设备上分布的技术。数据分片要达到三个目的:

    1. 分布均匀,即每台设备上的数据量要尽可能相近;
    2. 负载均衡,即每台设备上的请求量要尽可能相近;
    3. 扩缩容时产生的数据迁移尽可能少。

    数据分片方法

    数据分片一般都是使用Key或Key的哈希值来计算Key的分布,常见的几种数据分片的方法如下:

    1. 划分号段。这种一般适用于Key为整型的情况,每台设备上存放相同大小的号段区间,如把Key为[1, 10000]的数据放在第一台设备上,把Key为[10001, 20000]的数据放在第二台设备上,依次类推。这种方法实现很简单,扩容也比较方便,成倍增加设备即可,如原来有N台设备,再新增N台设备来扩容,把每台老设备上一半的数据迁移到新设备上,原来号段为[1, 10000]的设备,扩容后只保留号段[1, 5000]的数据,把号段为[5001, 10000]的数据迁移到一台新增的设备上。此方法的缺点是数据可能分布不均匀,如小号段数据量可能比大号段的数据量要大,同样的各个号段的热度也可能不一样,导致各个设备的负载不均衡;并且扩容也不够灵活,只能成倍地增加设备。
    2. 取模。这种方法先计算Key的哈希值,再对设备数量取模(整型的Key也可直接用Key取模),假设有N台设备,编号为0~N-1,通过Hash(Key)%N就可以确定数据所在的设备编号。这种方法实现也非常简单,数据分布和负载也会比较均匀,可以新增任何数量的设备来扩容。主要的问题是扩容的时候,会产生大量的数据迁移,比如从N台设备扩容到N+1台,绝大部分的数据都要在设备间进行迁移。
    3. 检索表。在检索表中存储Key和设备的映射关系,通过查找检索表就可以确定数据分布,这里的检索表也可以比较灵活,可以对每个Key都存储映射关系,也可结合号段划分等方法来减小检索表的容量。这样可以做到数据均匀分布、负载均衡和扩缩容数据迁移量少。缺点是需要存储检索表的空间可能比较大,并且为了保证扩缩容引起的数据迁移量比较少,确定映射关系的算法也比较复杂。
    4. 一致性哈希。一致性哈希算法(Consistent Hashing)在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot Spot)问题,该方法的详细介绍参考此处http://blog.csdn.net/sparkliang/article/details/5279393。一致性哈希的算法简单而巧妙,很容易做到数据均分布,其单调性也保证了扩缩容的数据迁移是比较少的。

    通过上面的对比,在这个系统选择一致性哈希的方法来进行数据分片。

    虚拟服务器

    为了让系统有更好的扩展性,这里提出存储层VServer(虚拟服务器)的概念,一个VServer是一个逻辑上的存储服务器,是分布式存储系统的一个存储单元,一台物理设备上可以部署多个VServer,一个VServer支持一个写进程和多个读进程。

    通过VServer的方式,会有下面一些好处:

    1. 提高单机性能。为了不引入复杂的锁机制,采用了单写进程的设计,如果单机只有一个写进程,写并发能力会受到限制,通过VServer方式把单机上的存储资源(内存、硬盘)划分为多个存储单元,这样就支持多个写进程同时工作,大大提升单机写并发能力。
    2. 部署扩展性更好。VServer的方式在部署上非常灵活,可以根据单机的资源情况来确定VServer的数量,针对不同的机型配置不同的VServer数量,这样不同的机型都能充分利用机器上的资源,即使在一个系统中使用多种机型,也能做到机器的负载比较均衡。

    一致性哈希的应用

    数据分片是在接口层实现的,目的是把数据均匀地划分到不同的VServer上。有了接口层的存在,逻辑层寻址就轻量了很多,寻址存储层VServer的工作全部由接口层负责,逻辑层只需要随机选一个接口层机器访问即可。

    接口层使用了一致性哈希的割环算法来实现数据分片,在割环算法中,为了让数据均匀分布到各个VServer,每个VServer需要有多个VNode(虚拟节点)。一个Key寻址的过程如下图所示,首先根据Hash(Key)在哈希环上找到对应的VNode,在根据VNode和VServer的映射表确定所属的VServer。

    由上述查找过程可知,需要事先离线计算出VNode在哈希环上的分布、VServer和VNode映射关系。为了是计算结果具有通用性,即在拥有任何数量VServer的一个系统都可以使用该结果得到一致性哈希的映射表,这就要求结果是与机器无关的,比如不能使用IP来计算VNode的哈希值。在计算前需要确定每个VServer包含的VNode数量,以及一个系统所支持的最大VServer数量。一个简单的方法是类似上文链接中提到的方法,但不能和IP相关,可以改用VServer和VNode的编号来计算哈希值,如Hash("1#1"),Hash("1#2")… 这种方法要求一个VServer包含的VNode的数量比较多,大概需要500个才能使各个VServer上的数据比较均匀。当然还有其他的一些方法做到一个VServer上包含更少的VNode数量,并且让数据分布偏差在一定范围内。

    Google提出了一种新的一致性哈希算法Jump Consistent Hash,此算法零内存消耗,均匀分配,快速,并且只有5行代码,优势非常明显,详细介绍见此处http://my.oschina.net/u/658658/blog/424161。和上面介绍的方法相比,一个最大的不同点是,在扩容重新分布数据时,在上面的方法中,新机器的一个VNode上的数据只会来自一个老机器上的VNode,而这种方法是会来自所有老机器上的VNode。这个问题可能会导致一些设计上复杂化,所以使用的时候要慎重考虑。


    转:http://www.cnblogs.com/Leo_wl/p/5654789.html


    分片模式是什么?

    数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。

    (1)一种是按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这种切分可以称之为数据的垂直(纵向)切分 

    (2)另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。

    分片相关的概念

    逻辑库(schema) :

    通常对实际应用来说,并不需要知道中间件的存在,业务开发人员只需要知道数据库的概念,所以数据库中间件可以被看做是一个或多个数据库集群构成的逻辑库。

    • 逻辑表(table):

    既然有逻辑库,那么就会有逻辑表,分布式数据库中,对应用来说,读写数据的表就是逻辑表。逻辑表,可以是数据切分后,分布在一个或多个分片库中,也可以不做数据切分,不分片,只有一个表构成。

    • 分片表:

    是指那些原有的很大数据的表,需要切分到多个数据库的表,这样,每个分片都有一部分数据,所有分片构成了完整的数据。 总而言之就是需要进行分片的表。

    • 非分片表:

    一个数据库中并不是所有的表都很大,某些表是可以不用进行切分的,非分片是相对分片表来说的,就是那些不需要进行数据切分的表。

    • 分片节点(dataNode)

    数据切分后,一个大表被分到不同的分片数据库上面,每个表分片所在的数据库就是分片节点(dataNode)。

    • 节点主机(dataHost)

    数据切分后,每个分片节点(dataNode)不一定都会独占一台机器,同一机器上面可以有多个分片数据库,这样一个或多个分片节点(dataNode)所在的机器就是节点主机(dataHost),为了规避单节点主机并发数限制,尽量将读写压力高的分片节点(dataNode)均衡的放在不同的节点主机(dataHost)。

    • 分片规则(rule)

    前面讲了数据切分,一个大表被分成若干个分片表,就需要一定的规则,这样按照某种业务规则把数据分到某个分片的规则就是分片规则,数据切分选择合适的分片规则非常重要,将极大的避免后续数据处理的难度。

    转:https://blog.csdn.net/weixin_38074050/article/details/78640004
    展开全文
  • 数据库概念及表操作

    千次阅读 2019-04-10 18:43:17
    数据库是用户存放数据、访问数据、操作数据的存储仓库,用户的各种数据被有组织的存放在数据库中。可以随时被有权限的用户查询、统计、添加、删除、和修改。 是长期存储在计算机内的,有组织、可共享的数据集合。...
  • 常用中文图书和期刊数据库 页面导航: 一、馆藏目录(OPAC或IPAC) 二、电子图书(超星、读秀) 三、电子期刊(知网\万方\维普) ...功能:书目检索、分类浏览、期刊导航、新书通报、购书推荐、信息发布、读者推...
  • 数据库

    千次阅读 2011-10-26 21:09:29
     严格地说,数据库是“按照数据结构来组织、存储和管理数据的仓库”。在经济管理的日常工作中,常常需要把某些相关的数据放进这样的“仓库”,并根据管理的需要进行相应的处理。例如,企业或事业单位的人事部门常常...
  • 数据库, 数据仓库, 数据集市,数据湖,数据中台

    千次阅读 多人点赞 2019-02-22 16:21:47
    大数据:数据仓库和数据库的区别 作者:南宫蓉 出处:简书 第一篇:数据仓库概述 第二篇:数据库关系建模 作者:穆晨 出处:CNBLOS 摘要 本文简要介绍数据库 数据仓库和数据集市概念,并做简要对比。 0x01 ...
  • DB2数据库

    千次阅读 2017-03-31 21:57:26
    转自:DB2数据库 开放分类:资料正规化 DB2是IBM一种分布式数据库解决方案。说简单点:DB2就是IBM开发的一种大型关系型数据库平台.它支持多用户或应用程序在同一条SQL 语句中查询不同...
  • 如果你经常关注知乎,就会发现,这个问题经常出现在你的feeds流里面,时长都会有各式各样的“删到跑路”事件发生。不管是传统数据库或者是云数据库,总会遇到一些问题,比如数据迁移,比如数据风险安全,比如数据...
  • 数据库编程总结

    万次阅读 热门讨论 2010-04-11 20:10:00
    数据库编程总结当前各种主流数据库有很多,包括Oracle, MS SQL Server, Sybase, Informix, MySQL, DB2, Interbase / Firebird, PostgreSQL, SQLite, SAP/DB, TimesTen, MS ACCESS等等。数据库编程是对数据库的创建、...
  • MySQL数据库学习

    千次阅读 2018-04-14 22:54:29
    数据库(DataBase):数据库是按照数据结构来组织、存储和管理数据的仓库。数据库管理系统(Database Management SystemDBMS):是专门用于管理数据库的计算机系统软件。数据库管理系统能够为数据库提供数据的定义、...
  • 1.数据库 按照早期的数据库理论,比较流行的数据库模型有三种,分别为层次式...用户通过查询来检索数据库中的数据,而查询是一个用于限定数据库中某些区域的执行代码。关系模型可以简单理解为二维表格模型,而一个关系
  • 数据库简史

    千次阅读 2020-02-27 09:47:49
    数据库简史 ● 一、RDBMS(关系数据库,Relational DBMS) ● 数据库 早期史 1961年,GE(通用电气公司,General Electric Company)的Charles Bachman ,开发了IDS(集成数据存储,Integrated Data Store),这是...
  • 数据库复习笔记(全覆盖,包括往年部分真题)

    万次阅读 多人点赞 2020-11-26 18:08:35
    ## 1、数据库系统概述 **1.1 数据库的基本概念** 数据库: 长期储存在计算机内、有组织的、可共享的大量数据的集合。 *基本特征:* 数据按一定的数据模型组织、描述和储存 ... 数据库管理系统及其功能: 位于...
  • 数据库面试

    千次阅读 多人点赞 2019-02-13 09:03:42
    一、数据库问答题 1. SQL语言包括哪些类型? 数据定义DDL:Create Table,Alter Table,Drop Table, Create/Drop Index等 数据操纵DML:Select ,insert,update,delete, 数据控制DCL:grant,revoke 2. 内联接,外联接...
  • 数据库基础与SQL基础知识整理

    万次阅读 2016-09-16 12:48:31
    PS:对数据库进行一些危险操作,一定要先备份 一.数据库简介 1. DBMS(DataBaseManagement System,数据库管理系统)和数据库数据库Schema有两种含义,一种是概念上的Schema,指的是一组DDL语句集,该语句集完整地...
  • 数据库编程

    千次阅读 2014-04-27 22:32:08
    当前各种主流数据库有很多,包括Oracle,MS SQL Server, Sybase, Informix, MySQL, DB2, Interbase / Firebird, PostgreSQL,SQLite, SAP/DB, TimesTen, MS ACCESS等等。数据库编程是对数据库的创建、读写等一列的操作...
  • [转] MySQL数据库安全配置

    千次阅读 2005-08-23 18:31:00
    2002-03-22文章属性:整理文章来源:http://www.xfocus.net文章提交:san (san_at_xfocus.org)MySQL数据库安全配置1、前言MySQL 是完全网络化的平台关系型数据库系统,同时是具有客户机/服务器体系结构的分布式...
  • MySQL:认识数据库_MySQL数据库的优点

    千次阅读 2019-04-17 19:40:45
    数据库文件:安全性高,存储数据快、检索速度快。 数据库 (Database)简称DB,是按照数据结构来组织、存储和管理数据的仓库,其本身可看作电子化的文件柜。用户可以对文件中的数据进行增加、删除、修改、查找等...
  • ORACLE-数据库

    2007-12-07 21:33:00
    1. oracle 是对象关系型数据库,它既提供关系数据库系统的功能,有提供面向对象数据库功能。在数据安全性与数据完整性控制方面的优越性能,以及操作系统,硬件平台的数据库互操作能力。 主要特点: 支持多...
  • MySQL数据库

    千次阅读 2019-05-29 17:20:22
    一、基本概念 1.主键、外键、超键、...主键:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。 外键:在一个表中存在...
  • 使用 HTML5 数据库和离线功能

    千次阅读 2014-02-12 18:22:50
    提供离线数据编辑和数据同步化 ...有了离线功能和本地持久存储特性,您不管是在线还是离线状态都可以交付同样丰富的用户体验,这些体验以前只可在专用的桌面应用程序开发框架中获得。在本文中,您将了解如何利用 HTM
  • 数据库性能优化详解

    万次阅读 多人点赞 2017-02-03 17:38:06
    1.数据库访问优化法则 要正确的优化SQL,我们需要快速定位能性的瓶颈点,也就是说快速找到我们SQL主要的开销在哪里?而大多数情况性能最慢的设备会是瓶颈点,如下载时网络速度可能会是瓶颈点,本地复制
  • 数据库性能优化

    千次阅读 2019-01-18 16:46:45
    1.单机优化 1.1.表结构设计 1.1.1.范式(规范) 什么样的表才是符合3NF (范式) ...只要数据库是关系型数据库(mysql/oracle/db2/sysbase/sql server),就自动的满足1NF.关系型数据库中是不允许分割列的。 2)...
  • 信息组织与检索 知识点整理 ...2.信息检索系统结构和功能模块 3.信息组织(信息采集,信息描述,信息标引,信息存储) 有点像知识点,事实上就是知识点,能举例的已经举例了,我尽力了。。 (会有粉丝吗呜呜呜

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 20,710
精华内容 8,284
关键字:

具有跨库检索功能的数据库是