MySql各个版本的DDL介绍

SQL语言一共分为4大类:数据定义语言DDL,数据操纵语言DML,数据查询语言DQL,数据控制语言DCL

DDL

数据定义语言DDL(Data Definition Language)
  • 对象: 数据库和表

  • 关键词: create alter drop truncate(删除当前表再新建一个一模一样的表结构)

  • 创建数据库:create database school;

  • 删除数据库:drop database school;

  • 切换数据库:use school;

  • 创建表:

		create table student(

      id int(4) primary key auto_increment,

      name varchar(20),

      score int(3)

    );
  • 查看数据库里存在的表:show tables;

注意:

  • varchar类型的长度是可变的,创建表时指定了最大长度,定义时,其最大值可以取0-65535之间的任意值,但记录在这个范围内,使用多少分配多少,

  • varchar类型实际占用空间为字符串的实际长度加1。这样,可有效节约系统空间。varchar是mysql的特有的数据类型。

  • char类型的长度是固定的,在创建表时就指定了,其长度可以是0-255之间的任意值。虽然char占用的空间比较大,但它的处理速度快。

  • 修改表:

alter table student rename (to) teacher;

alter table student add password varchar(20);

alter table student change password pwd varchar(20);

alter table student modify pwd int;

alter table student drop pwd;
  • 删除表:drop table student;

  • 查看生成表的sql语句:show create table student;

  • 查看表结构:desc student;

数据操纵语言DML(Data Manipulation Language)
  • 对象:纪录(行)

  • 关键词:insert update delete

  • 插入:
    insert into student values(01,'tonbby',99);(插入所有的字段)
    insert into student(id,name) values(01,'tonbby'); (插入指定的字段)

  • 更新:update student set name = 'tonbby',score = '99' where id = 01;

  • 删除:delete from tonbby where id = 01;

注意:

  • 开发中很少使用delete,删除有物理删除和逻辑删除,其中逻辑删除可以通过给表添加一个字段(isDel),若值为1,代表删除;若值为0,代表没有删除。此时,对数据的删除操作就变成了update操作了。

  • truncate和delete的区别:
    truncate是删除表,再重新创建这个表。属于DDL,delete是一条一条删除表中的数据,属于DML。

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

select ... from student where 条件 group by 分组字段 having 条件 order by 排序字段
执行顺序:from->where->group by->having->order by->select

注意:

  • group by 通常和聚合函数(avg(),count()…)一起使用 ,经常先使用group by关键字进行分组,然后再进行集合运算。

  • group by与having 一起使用,可以限制输出的结果,只有满足条件表达式的结果才会显示。

  • having和where的区别:
    两者起作用的地方不一样,where作用于表或视图,是表和视图的查询条件。having作用于分组后的记录,用于选择满足条件的组。

数据控制语言DCL(Data Control Language)

用户,权限,事务。

原文地址https://www.cnblogs.com/tonbby/p/tonbby.html

MySQL 5.5 DDL

在MySQL 5.5版本前,所有DDL操作都使用Copy Table的方式完成,操作过程中原表数据库不允许写入,只能读取,在MySQL 5.5版本中引入FIC(Fast index creation)特性。

FCI 操作流程:

  1. 对表加共享S锁,允许其他会话读操作,但禁止写操作
  2. 根据当前表数据创建索引
  3. 新索引创建完成,解除S锁,允许读写

FCI 优点:

  1. 创建索引不需要拷贝整表数据,创建速度快,
  2. 创建索引过程中,可以快速中止。

FCI限制:

  1. FCI特新仅限于复制索引,不试用于聚集索引
  2. 索引创建期间,表只允许读不允许写。

在MySQL 5.6.7版本前,DDL操作主要有copy和inplace两种方式,两种方式全程都需要锁表禁止写操作,允许部分时间段的读操作,inplace方式仅支持添加和删除索引两种方式。

copy方式:

  1. 新建带索引的临时表
  2. 锁原表,禁止DML,允许查询
  3. 将原表数据拷贝到临时表(无排序,一行一行拷贝)
  4. 进行rename,升级字典锁,禁止读写
  5. 完成创建索引操作

inplace方式:

  1. 新建索引的数据字典
  2. 锁表,禁止DML,允许查询
  3. 读取聚集索引,构造新的索引项,排序并插入新索引
  4. 等待打开当前表的所有只读事务提交
  5. 创建索引结束

MySQL 5.6 DDL

在MySQL 5.6.7版本后,引入了row_log来记录DDL期间写操作所产生的日志,因此除DDL操作开始和结束的两小段时间需要对表持EXCLUSIVE-MDL锁禁止读写外,其余DDL操作阶段允许其他回话对表进行读写,因此可算作ONLINE DDL。

对于ONLINE DDL操作,同样包含copy和inplace方式,而对于inplace方式,又可以细分为rebuild方式和no-rebuild方式,rebuild方式指需要重新组织记录的操作如添加删除列或交换列顺序等操作,而no-rebuild方式指不会导致记录格式发生变化的操作如删除和添加索引。

ONLINE DDL可分为三个阶段操作:

Prepare阶段:

  1. 创建新的临时frm文件
  2. 持有EXCLUSIVE-MDL锁,禁止读写
  3. 根据alter类型,确定执行方式(copy,online-rebuild,online-norebuild)
  4. 更新数据字典的内存对象
  5. 分配row_log对象记录增量
  6. 生成新的临时ibd文件

ddl执行阶段:

  1. 降级EXCLUSIVE-MDL锁,允许读写
  2. 扫描old_table的聚集索引每一条记录rec
  3. 遍历新表的聚集索引和二级索引,逐一处理
  4. 根据rec构造对应的索引项
  5. 将构造索引项插入sort_buffer块
  6. 将sort_buffer块插入新的索引
  7. 处理ddl执行过程中产生的增量(仅rebuild类型需要)

commit阶段

  1. 升级到EXCLUSIVE-MDL锁,禁止读写
  2. 重做最后row_log中最后一部分增量
  3. 更新innodb的数据字典表
  4. 提交事务(刷事务的redo日志)
  5. 修改统计信息
  6. rename临时idb文件,frm文件
  7. 变更完成

Online DDL期间产生Row Log会按照Block来存放和处理,回放Row Log时按照Block来处理,一个Block回放完后处理下一个Block,只有到达最后一个Block时才会锁表,保证最后一个Block完成后新数据和老数据保持一致,因此Online DDL期间产生大量Row Log不会导致表被长时间锁定。
仅需要修改元数据的DDL操作:

  1. 设置列默认值
  2. 设置自增列的自增值
  3. 删除索引

可以采用Online no-rebuild方式的DDL操作:

  1. 添加索引

可以采用Online rebuild方式的DDL操作:

  1. 添加列
  2. 删除列
  3. 交换列顺序
  4. 修改列NULL-NOTNULL属性
  5. 修改表ROW-FORMAT
  6. 添加修改主键

只能采用Copy方式的DDL操作:

  1. 修改列类型
  2. 转换字符集
  3. Optimize table
  4. 删除主键

PS: 从MySQL 5.6.17版本后,Optimize table可以采用Inplace方式操作。

Online DDL操作相关参数:

  1. innodb_sort_buffer_size:用来存放Row log的Block大小由参数innodb_sort_buffer_size控制。
  2. innodb_online_alter_log_max_size:控制整个DDL期间产生Row log的文件上限值,当产生的Row Log超过该上限值,则DDL操作失败,并回滚该期间所有未提交的并发DML操作。
  3. innodb_sort_buffer_size:在DDL执行期间Row Log会写入到一个日志文件,该日志文件每次按照innodb_sort_buffer_size来扩展。
  4. old_alter_table,当该参数被启用后,所有Alter操作将使用COPY方式操作。
    唯一索引的BUG:

(未找到该BUG出处)MySQL 在处理Row Log的时候存在BUG,会导致创建的唯一索引中可能存在不唯一KEY值的情况。
Duplicate entry问题:

在进行Online DDL操作过程中,可能遇到Duplicate entry的报错,但数据和修改命令都正常,该问题解释:

When running an online DDL operation, the thread that runs the ALTER
TABLE statement applies an “online log” of DML operations that were
run concurrently on the same table from other connection threads. When
the DML operations are applied, it is possible to encounter a
duplicate key entry error (ERROR 1062 (23000): Duplicate entry), even
if the duplicate entry is only temporary and would be reverted by a
later entry in the “online log”. This is similar to the idea of a
foreign key constraint check in InnoDB in which constraints must hold
during a transaction.
连接:https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-limitations.html

MySQL 5.7 DDL

在MySQL 5.7版本中,增加以下新功能:

支持修改索引名操作

操作语法:ALTER TABLE t1 RENAME INDEX idx1 to idx2;
该操作仅需要修改元数据信息和刷新缓存,因此修改操作能快速完成。
支持在线增加VARCHAR列的长度。

在Innodb存储引擎中,字节长度小于255的列使用1个字节来标识列长,而对于字节长度超过255的列需要使用2个字节来标识列长。

  1. 如果VARCHAR列长度仅在0-255或255-65535区间发生变化时,仅需要修改元数据信息而不需要对表进行Inplace操作,因此修改操作能快速完成。
    语法:alter table tb002 ALGORITHM=INPLACE, CHANGE COLUMN c4 c4 varchar(500);
    或: alter table tb002 ALGORITHM=INPLACE, modify c4 varchar(600);
  2. 如果VARCHAR列长度从0-255区间变化到255-65535区间,则只能使用COPY方式,不允许并发DML。
  3. 如果缩小VARCHAR列的长度,也只能使用COPY方式,不允许并发DML。
    支持使用INPLACE方式增加主键
    语法:ALTER TABLE tb002 ADD PRIMARY KEY(id),ALGORITHM=INPLACE;

MySQL DDL总结:
虽然MySQL 5.6和5.7版本提供了Online DDL操作,但Online DDL仍存在以下问题:

  1. 主从复制延迟,只有主库上DDL执行成功才会写入到binlog中,而DDL操作在从库上不能并发执行,因此即使主库执行DDL时允许并发DML操作,对于大表操作,仍会引发严重的复制延迟。
  2. 主库执行Online DDL时,不能根据负载暂停DDL操作。
  3. 使用Inplace方式执行的DDL,发生错误或被KILL时,需要一定时间的回滚期,执行时间越长,回滚时间越长。
  4. 使用Copy方式执行的DDL,需要记录过程中的undo和redo日志,同时会消耗buffer pool的资源,效率较低,优点是可以快速停止。
  5. Online DDL并不是所有时间段的Online,在特定时间段需要加元数据锁或其他锁。
  6. 允许并发DML的DDL,可能会导致Duplicate entry问题。

DDL 建议:

  1. 对于并发操作较高的表,无论表数据量多少,不能在业务高峰期操作,
  2. 对于大表和较大表,如果对复制延迟和主库性能敏感,建议改为gh-ost或pt-osc工具,
  3. 对于包含唯一索引创建的DDL,不能使用gh-ost或pt-osc工具,
  4. 能业务低峰期操作的DDL,都尽量安排在业务低峰期进行。

原文地址https://www.cnblogs.com/TeyGao/p/9089997.html

删除和更新对性能的影响

删除和更新操作的开销往往比插入高,所以一个好的设计需要减少对数据库的更新和删除操作。

更新操作

数据库的更新操作会带来一连串的“效应”:更新操作需要记录日志(以便错误时回滚);更新可变长字段(如,varchar类型)会带来数据物理存储的变化(记录的移动);更新索引字段会导致索引重建;更新主键会导致数据重组等。这一切不但会造成更新操作本身效率低,而且由于磁片碎片的产生会造成以后查询性能的降低。为了应对这一情况,有两种策略:一、减少更新次数,把多个字段的更新写到同一个语句里;二、避免更新。这两种策略分别适用于不同的情况,下面将举例说明两种情况。

1 减少更新次数
在整合库里有个代码清洗过程,就是通过连接代码表给业务数据的自编码字段赋值。代码清洗其实是通过关联代码表来更新业务数据表的一个过程,需要连接多个代码表,更新多个自编码字段。完成此更新,有两种更新语句的写法:一种是写成多个SQL语句,每个语句更新一个自编码字段;另一种写法是将所有更新写在一个语句中。更新银行代码的更新语句如下所示:

      updateTBL_INCOME_TMP A
        setBANKCODESELF = (
         select SELFCODE
         from
         TBL_BANKINFO B
         where A.BANKCODE = B.BANKCODE )

通过一个更新语句实现多个自编码字段更新的语句示意如下:

updateTBL_INCOME_TMP
set 代码1自编码 = 通过关联代码1表得到自编码,
    代码2自编码 =通过关联代码2表得到自编码,
    ...,
    代码n自编码 =通过关联代码n表得到自编码

利用两千万的测试数据。两种方法的测试结果如下表所示。从测试结果看出,一次更新方法性能提高了十倍,大大提高了性能。

处理过程多次更新方法耗时一次更新方法耗时
代码清洗0:29:480:02:59
  1. 避免更新

下面举个通俗的例子,这类情况是经常遇到的。某公司有一套系统员工考勤系统,为了提高查询统计的性能,在原有系统基础上建立了一些包含冗余信息的表。以员工表为例,它获得数据的过程如图所示。第一步把员工信息放到新表中,然后连接通过字段“部门ID”连接更新“部门名称”。
在这里插入图片描述
一般,为了节省存储开支把部门名称这样的字段设计成可变长的。所以在对它进行更新时会造成磁盘数据的重新组织,形成磁盘碎片,影响查询性能。

为了避免这样的情况发生,我们可以使用如图13所示的方法避免更新。这种方法一步完成了冗余数据表的插入,再插入时连接部门表获得“部门名称”,从而避免了更新操作。
在这里插入图片描述

删除操作

初学者可能认为删除操作很简单,可以快速完成。其实这是一个错误的理解,删除过程需要大量扫描磁盘;需要记录数据库日志;而且删除过程不释放磁盘空间,浪费磁盘,并且使磁盘上的数据支离破碎,这对后续查询的性能是一个致命的打击。通常用两种方式来应对:

  1. 对经常做删除操作的表进行重组(reorg);
  2. 避免删除。

重组

重组(reorg)操作会重新排列表数据的物理顺序,并除去碎片数据中的空闲空间。

由于删除操作不释放磁盘空间,在执行删除操作后,表会成为碎片状,这导致性能严重下降,在多次更新操作之后也会出现这种情况。若收集了统计信息,但看不出有明显的性能改进,则重组表数据可能会有帮助。重组表数据时,根据指定的索引重新安排数据的物理顺序,并除去碎片数据中的空闲空间。这使该数据可以更快速的被存取,从而改进性能。

避免删除
利用中间表和正式表模式

在数据需要比较复杂的处理的时候经常会用到中间表和正式表模式。数据在中间表中被处理,然后把满足条件的数据转移至正式表,不满足条件的数据保留在中间表中。图14示意了数据从中间表转移到正式表的过程:在完成数据处理之后,需要把中间表temp1中flag = 1的数据插入到正式表,并删除中间表temp1中flag = 1的数据。
在这里插入图片描述
因为flag字段不是聚簇索引,所以当对中间表temp1进行删除后,会再磁盘中留下大量碎片。不但会留下那么多的磁盘碎片,而且已删除的数据的空间也不会自动释放。结果是不但浪费磁盘空间,而且查询性能会急剧下降。
在这里插入图片描述

咱们可以使用清空表的命令来避免删除操作。除了中间表temp1和正式表,添加辅助临时表temp2。如果temp1中保留的数据flag=0只占有10%,这一优化将显著提升性能。具体步骤如下:

  1. 将temp1中flag=0的数据,插入到temp2

  2. 清空表temp1

复制代码 代码如下:

alter table temp1 ACTIVATE NOT LOGGED INITIALLY WITH EMPTY TABLE ;
3. 将temp2中的数据插入temp1

如何使访问更高效

本小节的内容很大一部分来自《The Art of SQL》这本书,这本书里集合了数据库开发的通用经验。虽然没有局限于具体的DBMS和硬件平台,但是却是一本实践性很强的书。

  1. 一次连接数据库,做很多事情。直到处理完,才断开连接。
  2. 一个SQL语句包含尽量多的操作。形象地说:几千个语句,借助游标不断循环,很慢。换成几个语句,处理同样的数据,还是很慢。换成一个语句,解决问题,最好。
  3. 接近DBMS核心。尽量使用数据库自带的函数。减少自定义函数。因为再聪明的数据库优化器也不认识自定义函数。
  4. 一个语句不要连接太多的表,建议的上限是5个。
  5. 将频繁更新的列集中起来:当更新某一行时,DB2 会记录进行更改的所有列,因此将频繁更新的列放到一起可以减少 DB2 的记录工作。这只是一个有关性能的小建议,因此不应为实现它而进行重大的应用程序或数据库设计修改。

原文地址https://my.oschina.net/goopand/blog/403991

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值