1 管理索引

  • 创建索引帮助
    help CREATE INDEX

  • 创建索引

    1. 指令
      CREATE INDEX
    2. 语法格式
      CREATE INDEX index_name ON tbl_name(index_col_name,…);
    3. 示例
      示例1:在students表中的取name的前十个字符字段增加索引名为idx_classid
      MariaDB [hellodb]> CREATE INDEX idx_name ON students(name(10));
      
      • 1
      示例2:创建复合索引,在(name,age)两个字段上建立复合索引
      MariaDB [hellodb]> CREATE INDEX idx_name_age ON students(name,age);
      
      • 1
      示例3:创建唯一键索引,关键字CREATE UNIQUE INDEX,唯一键命名时最好加上前缀以区分例如uni_idx
      MariaDB [hellodb]> CREATE UNIQUE INDEX  uni_idx_name ON students(name);
      
      • 1
  • 删除索引

    1. 语法格式
      DROP INDEX index_name ON tbl_name;
    2. 示例
      删除在字段students上的索引
      MariaDB [hellodb]> DROP INDEX idx_classid  ON  students;
      
      • 1
      删除唯一键,DROP INDEX或ALTER都可以
      MariaDB [hellodb]> ALTER TABLE students  DROP  KEY uni_idx_name; 
      
      • 1
  • 查看索引

    1. 语法格式
      SHOW INDEXES FROM [db_name.]tbl_name;
    2. 示例
      '不在表所在库,显示索引,需要指定库名'
      MariaDB [(none)]> SHOW INDEXES FROM hellodb.students;
      '进入表所在数据库后,可以省略'
      MariaDB [(none)]> use hellodb
      MariaDB [hellodb]> show index from students\G
      
      • 1
      • 2
      • 3
      • 4
      • 5
      查看复合索引,显示效果,以两行显示,键名相同,分为2部分
      *************************** 4. row ***************************
              Table: students
         Non_unique: 1
           Key_name: idx_name_age    <==具有相同的键名
       Seq_in_index: 1               <==表示Name在组合键的前面
        Column_name: Name
      *************************** 5. row ***************************
              Table: students
         Non_unique: 1
           Key_name: idx_name_age    <==与4都属于复合键,相同的键名
       Seq_in_index: 2               <==表示age在组合键的后面
        Column_name: Age
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      查看唯一键索引
      MariaDB [hellodb]> show index from students\G
      *************************** 2. row ***************************
              Table: students
         Non_unique: 0         <==主键和唯一键与其他索引的区别在于,此项为0
           Key_name: uni_idx_name
      
      • 1
      • 2
      • 3
      • 4
      • 5
  • 优化表空间:
    数据库中表数据文件,在删除数据后,所占空间不会自动释放,需要进行表空间优化才可以释放

    1. 语法格式
      OPTIMIZE TABLE tb_name
    2. 示例
      MariaDB [hellodb]> OPTIMIZE TABLE students;
      
      • 1
  • 查看索引的使用

    1. 语法格式
      SHOW INDEX_STATISTICS
    2. 开启功能相关变量
      userstat
    3. 示例
      需要修改变量userstat为启动状态
      '1. 查看变量状态'
      MariaDB [hellodb]> SHOW VARIABLES LIKE 'userstat';
      +---------------+-------+
      | Variable_name | Value |
      +---------------+-------+
      | userstat      | OFF   |
      +---------------+-------+
      '2. 修改状态'
      MariaDB [hellodb]> SET GLOBAL userstat=1;
      '3. 查看索引的使用情况'
      MariaDB [hellodb]> SHOW INDEX_STATISTICS;
      +--------------+------------+------------+-----------+
      | Table_schema | Table_name | Index_name | Rows_read |
      +--------------+------------+------------+-----------+
      | hellodb      | students   | index_age  |        24 |
      +--------------+------------+------------+-----------+
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
  • EXPLAIN分析索引的有效性

    1. 关键字
      EXPLAIN
    2. 语法格式
      EXPLAIN SELECT clause
      '查询优化器如何执行查询'
      MariaDB [hellodb]> EXPLAIN  SELECT * 	FROM  students WHERE  age=20;
      +------+-------------+----------+------+--------	-------+-----------+---------+-------+------+-------+
      | id   | select_type | table    | type | possible_keys | key       | key_len | ref   | rows | Extra |
      +------+-------------+----------+------+---------------+-----------+---------+-------+------+-------+
      |    1 | SIMPLE      | students | ref  | index_age     | index_age | 1       | const |    2 |       |
      +------+-------------+----------+------+---------------+-----------+---------+-------+------+-------+
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    3. 输出信息说明:
      参考https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
      1. id
        当前查询语句中,每个SELECT语句的编号,包括子句的编号
        复杂类型的查询有三种:
        1. 简单子查询
        2. 用于FROM中的子查询
        3. 联合查询:UNION,UNION查询的分析结果会出现一个额外匿名临时表
          MariaDB [hellodb]> EXPLAIN SELECT  name  FROM students UNION SELECT name FROM teachers;
          +------+--------------+------------+-------+---------------+--------------+---------+------+------+-------------+
          | id   | select_type  | table      | type  | possible_keys | key          | key_len | ref  | rows | Extra       |
          +------+--------------+------------+-------+---------------+--------------+---------+------+------+-------------+
          |    1 | PRIMARY      | students   | index | NULL          | idx_name_age | 153     | NULL |   25 | Using index |
          |    2 | UNION        | teachers   | ALL   | NULL          | NULL         | NULL    | NULL |    4 |             |
          | NULL | UNION RESULT | <union1,2> | ALL   | NULL          | NULL         | NULL    | NULL | NULL |             |
          +------+--------------+------------+-------+---------------+--------------+---------+------+------+------
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
    4. select_type
      1. 简单查询为SIMPLE
      2. 复杂查询select_type显示内容
        1. SUBQUERY:简单子查询
        2. PRIMARY:最外面的SELECT
        3. UNION:UNION语句的第一个之后的SELECT语句
        4. UNION RESULT: 匿名临时表
        5. DERIVED:用于FROM中的子查询
          要显示FROM子查询的类型,需要设置变量optimizer_switch,其中的相关项’derived_merg
          MariaDB [hellodb]> SET optimizer_switch='derived_merge=off';
          
          • 1
    5. table:SELECT语句关联到的表
    6. type:关联类型或访问类型,即MySQL决定的如何去查询表中的行的方式,以下顺序,性能从低到高
      1. ALL:全表扫描,也就是没有利用索引
      2. index:根据索引的次序进行全表扫描;如果在Extra列出现“Using index”表示了使用覆盖索引,而非全表扫描
      3. range:有范围限制的根据索引实现范围扫描;扫描位置始于索引中的某一点,结束于另一点
      4. ref: 根据索引返回表中匹配某单个值的所有行
      5. eq_ref:仅返回一个行,但与需要额外与某个参考值做比较
      6. const, system: 直接返回单个行
    7. possible_keys:查询可能会用到的索引
    8. key:查询中使用到的索引
    9. key_len:在索引使用的字节数
    10. ref:在利用key字段所表示的索引完成查询时所用的列或某常量值
    11. rows:MySQL估计为找所有的目标行而需要读取的行数
    12. Extra:额外信息
      1. Using index:MySQL将会使用覆盖索引,以避免访问表
      2. Using where:MySQL服务器将在存储引擎检索后,再进行一次过滤
      3. Using temporary:MySQL对结果排序时会使用临时表
      4. Using filesort:对结果使用一个外部索引排序
  1. 示例
    1. 索引没有利用,在表数据不是很多时范围查询,查询结果占表数据的很大一部分,优化器认为直接搜索的速度比索引快:
      '查看表students中以x开头的姓名,由下例可知,没有利用索引,因为此表一共只有25条记录,而x开头的行占了6条'
      MariaDB [hellodb]> EXPLAIN SELECT * FROM  students WHERE  name LIKE 'x%';
      +------+-------------+----------+------+---------------+------+---------+------+------+-------------+
      | id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows | Extra       |
      +------+-------------+----------+------+---------------+------+---------+------+------+-------------+
      |    1 | SIMPLE      | students | ALL  | index_name    | NULL | NULL    | NULL |   25 | Using where |
      +------+-------------+----------+------+---------------+------+---------+------+------+-------------+
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    2. 冗余索引示例,前文中已经建立了idx_name和复合键idx_name_age索引,试着搜索名字以o开头的学员,得到可用索引如下所示,复合键的索引机制为左前缀,而复合键idx_name_age的name键在左边,属于重复现象:
      MariaDB [hellodb]> EXPLAIN SELECT * FROM students WHERE name LIKE 'o%';
      +------+-------------+----------+-------+-------------------------+------------+---------+------+------+-----------------------+
      | id   | select_type | table    | type  | possible_keys           | key        | key_len | ref  | rows | Extra                 |
      +------+-------------+----------+-------+-------------------------+------------+---------+------+------+-----------------------+
      |    1 | SIMPLE      | students | range | index_name,idx_name_age | index_name | 152     	| NULL |    1 | Using index condition |
      +------+-------------+----------+-------+-------------------------+------------+---------+------+------+-----------------------+
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
  • 另一个查询优化SQL语句
    如果查询命令是一个多表查询,想要知道具体哪个字查询拖慢了速度,explain显示的内容不够具体,需要另一个观察命令的执行过程变量profiling,默认是关闭的
    1. '启用变量'
    MariaDB [hellodb]> SET profiling=on;
    2. '执行一个查询指令'
    MariaDB [hellodb]> SELECT a.stuid, a.name  FROM   (SELECT * FROM students) AS a;
    3. '执行profiles观察查询过程'
    MariaDB [hellodb]> SHOW profiles;
    +----------+------------+--------------------------------------------------------------+
    | Query_ID | Duration   | Query                                                        |
    +----------+------------+--------------------------------------------------------------  |
    |        1 | 0.00120368 | SELECT a.stuid, a.name  FROM   (SELECT * FROM students) AS a |
    +----------+------------+--------------------------------------------------------------+
    4. '针对编号继续查询,就会列出详细执行过程所用时间'
    MariaDB [hellodb]> SHOW profile FOR query 1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

2. 并发控制

保证多个用户同时访问,互相不干扰

2.1 一些概念

  • 锁分类

    1. 锁粒度
      1. 表级锁(MyISAM)
      2. 行级锁(InnoDB)
    2. 以独占性来分
      1. 读锁:共享锁,只读不可写,多个读互不阻塞,
      2. 写锁:独占锁,排它锁,一个写锁会阻塞其它读和它锁
    3. 按是否自动加锁分类:
      1. 隐式锁:由存储引擎自动施加锁
      2. 显式锁:用户手动请求
  • 实现

    1. 存储引擎:自行实现其锁策略和锁粒度
    2. 服务器级:实现行锁,表级锁;用户可显式请求
  • 锁策略
    在锁粒度及数据安全性寻求的平衡机制,加锁的缺点为影响并发性,但是可以保证数据完整性,在两者之间寻求平衡

2.2 显式锁使用

  • 加锁
    1. SQL语句关键字
      LOCK TABLES
    2. 语法格式
      LOCK TABLES   tbl_name[[AS] alias] lock_type  [, tbl_name[[AS] alias] lock_type] ...
      
      • 1
    3. 说明
      1. tbl_name:将加锁的表名
      2. lock_type: READ |WRITE
        WRITE锁时,需要注意缓存是否开启,如果有缓存需要重启服务或者关闭缓存开关或者将缓存相关的服务器变量quer_cache_wlock_invalidate=on写入配置文件,不允许其他用户从缓存读取
    4. 示例
      为表teachers加读锁
      MariaDB [hellodb]> LOCK TABLES teachers READ;
      此时不能访问本数据库的其他表格,会报错,其他终端不影响
      '试着访问同数据库的另一种表students'
      MariaDB [hellodb]> SELECT * FROM students;
      ERROR 1100 (HY000): Table 'students' was not locked with LOCK TABLES    <==报错信息
      
      • 1
      • 2
      • 3
      • 4
      • 5
  • 加全局锁
    1. 语法格式
      FLUSH TABLES [tb_name[,…]] [WITH READ LOCK]
    2. 说明
      将表加锁,关闭正在打开的表(清除查询缓存),不指定表,将进行全局加锁(所有数据库),通常在备份前加全局读锁,FLUSH TABLES为温备份,加锁时会等待所有表格关闭
    3. 示例:使用FLUSH TABLES加锁时,有未关闭表等待状态示例
      '在其他终端访问hellodb数据库表teachers,设置函数sleep(100)休眠100秒,保持访问状态'
      MariaDB [hellodb]> SELECT *,sleep(100) FROM teachers;
      '利用FLUSH TABLES 为teachers加只读锁'
      MariaDB [hellodb]> FLUSH TABLES teachers WITH READ LOCK;
        									        <==会卡在这里等待所有表关闭
      
      • 1
      • 2
      • 3
      • 4
      • 5
  • 查询时加锁
    1. 加写锁
      SELECT clause FOR UPDATE
    2. 加读锁
      SELECT clause LOCK IN SHARE MODE
  • 解锁
    UNLOCK TABLES

2.3 死锁

  • 什么是死锁
    两个或多个事务在相互占用彼此资源,并请求锁定对方占用的资源的状态
    MySQL4
  • 解决方法
    回滚其中一个,被回滚的是代价小的,通常为执行时间短的哪个事务,系统主动解决
  • 当多事务同时执行时,遇到行锁锁定,另一个用户处于等待状态的主动解决方案
    1. 查看事务列表
      SHOW PROMCESSLIST
    2. 结束等待事务
      kill id
    3. 示例
      1. '查看事务列表,找出处于等待的'
      MariaDB [hellodb]> SHOW PROMCESSLIST\G
      *************************** 7. row ***************************
            Id: 23          <==kill命令后面的编号
          User: root
          Host: localhost
            db: hellodb
       Command: Query
          Time: 21
         State: updating
          Info: update teachers set age=70 where tid=3     <==处于等待的事务
      Progress: 0.000
      2. '主动将结束等待状态'
      MariaDB [hellodb]> kill 23     <==id为等待事务编号
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

3. 事务

事务Transactions:一组原子性的SQL语句,或一个独立工作单元,有专门的事务日志记录操作过程,实现undo,redo等故障恢复功能,来保证数据的一致性

  • ACID特性:

    1. A(atomicity原子性)
      整个事务中的所有操作要么全部成功执行,要么全部失败后回滚
      数据库执行事务时,先读入数据到内存,在内存中修改后,放到日志文件中,全部事务执行完毕后会有一个标记,如果执行过程中掉电,恢复供电后,日志文件会根据标记判断事务是否全部执行完毕,全部执行完毕则写入磁盘(redo),没有执行完则舍弃以记录操作(undo),保证磁盘数据完整性
    2. C(consistency一致性)
      数据库总是从一个一致性状态转换为另一个一致性状态
    3. I(Isolation隔离性)
      一个事务所做出的操作在提交之前,是不能为其它事务所见;隔离有多种隔离级别,实现并发
    4. D(durability持久性)
      一旦事务提交,其所做的修改会永久保存于数据库中
  • Transaction生命周期
    MySQL4

    1. LNITIAL DB STATE :数据库初始一致性状态
    2. START TRANSACTION:开始事务,对数据库增删改
    3. COMMIT:确定无误,提交结果,结束事务
    4. NEW DB STATE:新的一致性状态
    5. ROLLBACK:只要事务没有提交,就可以回滚到数据库初始状态
  • 使用事务
    在数据库中执行增删改就是一个事务,回车执行就结束了此事务,这种系统后台自动开始,自动提交的事务叫做隐式提交事务,mysql和sql server默认使用自动提交,oracle默认使用的是手动提交需要输入(commit提交,rollback回滚)

    1. 自动提交是否启动相关变量
      set autocommit={1|0} 默认为1,设为0时为非自动提交

      '1. 在会话A中,将事务提交设置为非自动提交'
      MariaDB [(none)]> set autocommit=off;
      '2. 确认变量状态'
      MariaDB [(none)]>  show variables like 'autocommit';
      +--------------------------+-------+
      | Variable_name            | Value |
      +--------------------------+-------+
      | autocommit               | OFF   |   <==已经关掉,会话级的,不影响其他窗口
      +--------------------------+-------+
      3. '修改数据'
      MariaDB [hellodb]> UPDATE students SET classid=10 SHERE stuid=15;
      MariaDB [hellodb]> SELECT * FROM students;   <==在执行修改命令的终端查看修改	效果
      |    15 | Duan Yu       |  19 | M      |      10 |      NULL |    <=可以看到已修改
      4. '在B会话中查看'
      MariaDB [hellodb]> SELECT * FROM students;
      |    15 | Duan Yu       |  19 | M      |       4 |      NULL |    <=由于事务没有提交,属于脏数	据,其他会话不会显示
      5. '回到A会话,不想修改执行rollback,回滚到最初状态'
      MariaDB [hellodb]> ROLLBACK;
      Query OK, 0 rows affected (0.00 sec)
      6. '查看回滚后的结果,数据不变'
      MariaDB [hellodb]> select * from students;
      |    15 | Duan Yu       |  19 | M      |       4 |      NULL | 
      7. '确认事务无误,提交事务关键字为`commit`,确认后数据就永久更改,不能回滚了'
       MariaDB [hellodb]> COMMIT; 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
    2. 人为定义启动事务(以下3个命令都可以)

      1. BEGIN
      2. BEGIN WORK
      3. START TRANSACTION
    3. 结束事务:

      1. COMMIT:提交
      2. ROLLBACK: 回滚
        注意:只有事务型存储引擎中的DML语句方能支持此类操作
    4. 事务保存点

      1. SQL关键字
        SAVEPOINT identifier
      2. 回滚到保存点语法格式
        ROLLBACK [WORK] TO [SAVEPOINT] identifier
      3. 删除保存点
        RELEASE SAVEPOINT identifier
      4. 示例:事务在执行增删改时增加保存点,当执行回滚操作时,可以只撤销一部分
        '1. 开启事务'
        MariaDB [hellodb]> BEGIN;         
        Query OK, 0 rows affected (0.00 sec)
        2. '修改students表stuid为23的学员classid编号为15'
        MariaDB [hellodb]> UPDATE students SET classid=15 WHERE stuid=23;
        3. '设置保存点,命名为sp23'
        MariaDB [hellodb]> savepoint  sp23;
        4. '修改同上'
        MariaDB [hellodb]> UPDATE students SET classid=16 WHERE stuid=24;
        5. '设置保存点'
        MariaDB [hellodb]> savepoint  sp24;
        6. '修改同上'
        MariaDB [hellodb]> UPDATE students SET classid=17 WHERE stuid=25;
        7. '查看修改后的数据,如下所示'
        MariaDB [hellodb]> SELECT * FROM students;
        |    23 | Ma Chao       |  23 | M      |      15 |      NULL |
        |    24 | Xu Xian       |  27 | M      |      16 |      NULL |
        |    25 | Sun Dasheng   | 100 | M      |      17 |      NULL |
        8. '回滚到保存点sp24,可以看到只有25号学员信息返回原状态'
        MariaDB [hellodb]> ROLLBACK  TO  sp24;
        |    23 | Ma Chao       |  23 | M      |      15 |      NULL |
        |    24 | Xu Xian       |  27 | M      |      16 |      NULL |
        |    25 | Sun Dasheng   | 100 | M      |    NULL |      NULL |
        9. '回滚到保存点sp23,可以看到23号学员修改信息没有改变'
        MariaDB [hellodb]> ROLLBACK  TO  sp23 ;
        |    23 | Ma Chao       |  23 | M      |      15 |      NULL |
        |    24 | Xu Xian       |  27 | M      |    NULL |      NULL |
        |    25 | Sun Dasheng   | 100 | M      |    NULL |      NULL |
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
  • 事务隔离级别

相关文章:

  • 2021-06-12
  • 2022-01-23
  • 2022-12-23
猜你喜欢
  • 2021-12-20
  • 2021-11-03
  • 2022-12-23
  • 2021-09-12
  • 2021-09-03
  • 2022-01-16
  • 2021-05-11
相关资源
相似解决方案