• mysql常见问题理解及处理


    事务四大特性ACID

    • 原子性:要么同时成功,要么同时失败
    • 一致性:数据的一致性,有增就有减。
    • 隔离性:各个连接是独立的
    • 持久性:提交成功后写道磁盘。

    事务隔离级别

    未提交读(Read Uncommitted):允许脏读,其他事务只要修改了数据,即使未提交,本事务也能看到修改后的数据值。也就是可能读取到其他会话中未提交事务修改的数据

    提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)。

    可重复读(Repeated Read):可重复读。无论其他事务是否修改并提交了数据,在这个事务中看到的数据值始终不受其他事务影响。

    串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞(select * from sr_main where PK_SR_MAIN = '1265185686872899584' lock in share mode;--加共享锁

    select * from sr_main where PK_SR_MAIN = '1265185686872899584' for UPDATE;--加排他锁

    MySQL数据库(InnoDB引擎)默认使用可重复读( Repeatable read)

    查询mysql事务隔离级别
    1.查看当前会话隔离级别
    select @@tx_isolation;
    2.查看系统当前隔离级别
    select @@global.tx_isolation;
    3.设置当前会话隔离级别
    set session transaction isolatin level repeatable read;
    4.设置系统当前隔离级别
    set global transaction isolation level repeatable read;
    5.命令行,开始事务时
    set autocommit=off 或者 start transaction
    关于隔离级别的理解
    1.read uncommitted
    可以看到未提交的数据(脏读),举个例子:别人说的话你都相信了,但是可能他只是说说,并不实际做。
    2.read committed(解决脏读)
    读取提交的数据。但是,可能多次读取的数据结果不一致(不可重复读,幻读)。用读写的观点就是:读取的行数据,可以写。
    3.repeatable read(MySQL默认隔离级别,解决不可重复读)
    可以重复读取,但有幻读。读写观点:读取的数据行不可写,但是可以往表中新增数据。在MySQL中,其他事务新增的数据,看不到,不会产生幻读。采用多版本并发控制(MVCC)机制解决幻读问题。
    4.serializable

    索引相关

    mysql加索引及索引失效的情况

    前言:B+TREE索引的本质是多路绝对平衡查找树磁盘指针根节点保存子节点的地址,相当于书的目录,索引不是越多越好。

    一:如何加索引

    1.PRIMARY  KEY(主键索引)
            mysql>ALTER  TABLE  `table_name`  ADD  PRIMARY  KEY (  `column`  ) 
    2.UNIQUE(唯一索引)
            mysql>ALTER  TABLE  `table_name`  ADD  UNIQUE (`column` ) 
    3.INDEX(普通索引)
            mysql>ALTER  TABLE  `table_name`  ADD  INDEX index_name (  `column`  )
    4.FULLTEXT(全文索引)
            mysql>ALTER  TABLE  `table_name`  ADD  FULLTEXT ( `column` )
    5.多列索引
            mysql>ALTER  TABLE  `table_name`  ADD  INDEX index_name (  `column1`,  `column2`,  `column3`  )

    二:索引失效的情况

    1.like %开头,索引无效;当like前缀没有%,后缀有%时,索引有效。(违背最左匹配原则)

    2.or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效

    3.组合索引,不是使用第一列索引,索引失效。

    4.数据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int,使索引无效,产生全表扫描。

    5.在索引列上使用 IS NULL IS NOT NULL操作。索引是不索引空值的,所以这样的操作不能使用索引,可以用其他的办法处理,例如:数字类型,判断大于0,字符串类型设置一个默认值,判断是否等于默认值即可。

    6.在索引字段上使用not<>!=不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 优化方法: key<>0 改为 key>0 or key<0

    7.对索引字段进行计算操作、字段上使用函数

    三:EXPLAIN 查看sql执行计划(possible key:可能命中的索引;key:实际命中的索引)

    EXPLAIN select * from sr_main where mhzsfz = '330127199210021719' ; -- 0.227s
    EXPLAIN select * from sr_main where mhzsfz = '330127199210021719' and sys_scbj = 0 and sys_spzt = 1; -- 0.142s

    索引的等级:system>const>eq_ref>ref>range >index>ALL

    typerange以上才是有效索引

    select_type :查询类型

    simple简单查询 primary 主查询 UNION 第二个或者后面的查询语句。SUBQUERY : 子查询中的第一个select]

    table :输出结果的表

    type:查询级别

    typeALL 全表扫描,

    typeindex 索引全扫描,遍历整个索引来查询匹配的行
    type=range 索引范围扫描,常见于 <,<=,>,>=,between,in等操作符。
      例
        explain select * from adminlog where id>0 ,
        explain select * from adminlog where id>0 and id<=100
        explain select * from adminlog where id in (1,2)

    type=ref 使用非唯一索引或唯一索引的前缀扫描,返回匹配某个单独值的记录行。ref还经常出现在JOIN操作中
    type=eq_ref 类似于ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中有一条记录匹配;简单来说,说是多表连接中使用 主建或唯一健作为关联条件
    type=const/system 单表中最多有一个匹配行。主要用于比较primary key [主键索引]或者unique[唯一]索引,因为数据都是唯一的,所以性能最优。条件使用=
    type=NULL 不用访问表或者索引,直接就能够得到结果

     

    4possible_keys : 可能使用的索引列表.

    5key : 实现执行使用索引列表
    6key_len : 索引的长度
    7ref : 显示使用哪个列或常数与key一起从表中选择行。
    8row : 执行查询的行数,简单且重要,数值越大越不好,说明没有用好索引

    四:索引建立的原则(针对b+tree数据结构,如innodb存储引擎)

    1.B+Tree数据结构为,多路绝对平衡查找树,数据存储在叶子节点(普通b-tree数据存储在磁盘块中,一个磁盘块默认大小为16kb),树结构越矮胖,查找效率越高;

    2.索引长度能少则少,因为加入分子为16kb,分母越小,树的枝干越多(矮胖原则)

    3.索引不是越多越好,越全越好,一定要建立合适的,因为索引本身也消耗资源和性能

    4.like 999%不一定命中索引(还得看索引的离散性,越是唯一越能命中,选择性越好),但是like '%999%'‘%99999’一定不能命中索引

    5.where条件中的not in<>无法使用索引

    6.匹配范围值,order by也可命中索引

    7.多列指定查询,少用select *

    8.联合索引(多列索引)如果不是按照索引最左列开始查找,无法使用索引。

    9.联合索引中精确匹配最左前列并范围匹配另外其他列可以用到索引

    10联合索引如果查询中有个列的范围查询,则其右边的所有列都无法使用索引。

    sql语句分类:

    • DDL:数据定义语言(create drop)

    SET FOREIGN_KEY_CHECKS=0; -- 取消外键约束

    -- ----------------------------

    -- Table structure for sr_main

    -- ----------------------------

    DROP TABLE IF EXISTS `sr_main`;

    CREATE TABLE `sr_main` (

      `PK_SR_MAIN` varchar(50) NOT NULL COMMENT '主键',

      `QHMC` varchar(255) DEFAULT NULL COMMENT '行政区划名称',

      `MJTRK` decimal(65,0) DEFAULT '0' COMMENT '家庭人口',

      `MZFZMJ` double(20,2) DEFAULT '0.00' COMMENT '住房面积',

      `MBZ` text COMMENT '备注',

      PRIMARY KEY (`PK_SR_MAIN`)

    ) ENGINE=InnoDB AUTO_INCREMENT=469612 DEFAULT CHARSET=utf8;

    • DML:数据操作语句(insert update delete)
    • DQL数据查询语句select 
    • DCL数据控制语句,进行授权和权限回收grant revoke
    • TPL数据事务语句commit collback savapoint

     

     

    数据库三范式:

    第一范式:1NF是对属性的原子性约束,要求字段具有原子性,不可再分解(只要是关系型数据库都满足1NF)

    第二范式:2NF是在满足第一范式的前提下,非主键字段不能出现部分依赖主键;解决:消除复合主键就可避免出现部分以来,可增加单列关键字。

    • 第三范式:3NF是在满足第二范式的前提下,非主键字段不能出现传递依赖,比如某个字段a依赖于主键,而一些字段依赖字段a,这就是传递依赖。解决:将一个实体信息的数据放在一个表内实现。

     

     

    脏读幻读、不可重复读

    脏读: 是指事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的。

    不可重复读 :是指在数据库访问时,一个事务范围内的两次相同查询却返回了不同数据。在一个事务内多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么在第一个事务中的两次读数据之间,由于第二个事务的修改,第一个事务两次读到的的数据可能是不一样的。这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

    幻读: 是指当事务不是独立执行时发生的一种现象,比如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么就会发生,操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。 

    不可重复读&幻读区别:

    如果使用锁机制来实现这两种隔离级别,在可重复读中,sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。

    不可重复读重点在于update和delete,而幻读的重点在于insert。如何通过锁机制来解决他们产生的问题

      

    存储引擎 MyISAM  InnoDB区别:

     

    1. InnoDB支持事务MyISAM不支持。
    2. MyISAM适合查询以及插入为主的应用InnoDB适合频繁修改以及涉及到安全性较高的应用。
    3. InnoDB支持外键MyISAM不支持。
    4. MySQL5.5.5以后,InnoDB默认引擎
    5. 清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表。MyisAM使用delete语句删除后并不会立刻清理磁盘空间,需要定时清理,命令:OPTIMIZE table dept;
    6. InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’
    7. Myisam创建表生成三个文件:.frm 数据表结构  .myd 数据文件  .myi 索引文件,Innodb只生成一个 .frm文件,数据存放在.ibd文件
    8. 现在一般都选用InnoDB,主要是MyISAM的全表锁读写串行问题,并发效率锁表,效率低,MyISAM对于读写密集型应用一般是不会去选用的
    9. 应用场景:

     

      • MyISAM不支持事务处理等高级功能,但它提供高速存储和检索,以及全文搜索能力。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。
      • InnoDB用于需要事务处理的应用程序,包括ACID事务支持。如果应用中需要执行大量的INSERTUPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。

     

     

    CHARVARCHAR的区别:

    1. char类型的长度是固定的,varchar的长度是可变的。

       这就表示,存储字符串'abc',使用char(10),表示存储的字符将占10个字节(包括7个空字符)

                  使用varchar2(10),,则表示只占3个字节,10是最大值,当存储的字符小于10时,按照实际的长度存储。

    • CHAR列长度固定为创建表时声明的长度,长度值范围是1到255
    • 当CHAR值被存储时,它们被用空格填充到特定长度,检索CHAR值时需删除尾随空格。

     

     

    Mysql中的锁类型

    • MyISAM支持表锁,InnoDB支持表锁和行锁,默认为行锁
    • 表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低
    • 行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高

     

     

    存储过程

    我们常用的操作数据库语言SQL语句在执行的时候需要要先编译,然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。(理解为:一个方法不需要编译了,直接传参数就行;普通的sql是需要经历优化和编译的)

    一个存储过程是一个可编程的函数,它在数据库中创建并保存。它可以有SQL语句和一些特殊的控制结构组成。当希望在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟。它允许控制数据的访问方式。

    优点:

    (1).存储过程增强了SQL语言的功能和灵活性。存储过程可以用流控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。

    (2).存储过程允许标准组件是编程。存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,对应用程序源代码毫无影响。

    (3).存储过程能实现较快的执行速度。如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。

    (4).存储过程能过减少网络流量。针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织程存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大增加了网络流量并降低了网络负载。

    (5).存储过程可被作为一种安全机制来充分利用。系统管理员通过执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。

     

     

    delete、drop、truncate区别

    • truncate  delete只删除数据,不删除表结构 ,drop删除表结构,并且释放所占的空间。
    • 删除数据的速度drop> truncate > delete
    • delete属于DML语言,需要事务管理commit之后才能生效droptruncate属于DDL语言,操作立刻生效,不可回滚。
    • 使用场合:
      • 当你不再需要该表时,  drop;
      • 当你仍要保留该表,但要删除所有记录时,  truncate;
      • 当你要删除部分记录时always with a where clause),  delete.

     

    注意: 对于有主外键关系的表,不能使用truncate而应该使用不带where子句的delete语句,由于truncate不记录在日志中,不能够激活触发器

     

    数据库编码

    1.查看数据库编码格式

    mysql> show variables like 'character_set_database';

     2.查看数据表的编码格式

    mysql> show create table <表名>;

     3.创建数据库时指定数据库的字符集

    mysql>create database <数据库名> character set utf8;

    4.创建数据表时指定数据表的编码格式

    create table tb_books (

        name varchar(45) not null,

        price double not null,

        bookCount int not null,

        author varchar(45) not null ) default charset = utf8;

    5.修改数据库的编码格式

    mysql>alter database <数据库名> character set utf8;

    6.修改数据表格编码格式

    mysql>alter table <表名> character set utf8;

    7.修改字段编码格式

    mysql>alter table <表名> change <字段名> <字段名> <类型> character set utf8;

     

    mysql>alter table user change username username varchar(20) character set utf8 not null;

     8.添加外键

    mysql>alter table tb_product add constraint fk_1 foreign key(factoryid) references tb_factory(factoryid);

    mysql>alter table <表名> add constraint <外键名> foreign key<字段名> REFERENCES <外表表名><字段名>;

    9.删除外键

    mysql>alter table tb_people drop foreign key fk_1;

    mysql>alter table <表名> drop foreign key <外键名>;

  • 相关阅读:
    [BZOJ1415]聪聪和可可
    [POJ2096]Collecting Bugs
    开博第一天
    实现CSS样式垂直水平完全居中
    Vue中独立组件之间数据交互
    python Template中substitute()的使用
    eclipse 编辑 python 中文乱码的解决方案
    java Math.random()随机数的产生
    java文件读写的两种方式
    My way on Linux
  • 原文地址:https://www.cnblogs.com/tongcc/p/13714786.html
Copyright © 2020-2023  润新知