数据库篇(5)—存储引擎、索引和EXPLAIN

                                 存储引擎、索引和EXPLAIN

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

1、存储引擎

MySQL5.5.5前默认的数据库引擎为MyISAM,之后的是InnoDB,现在新版本是InnoDB的加强版XtraDB

(1)MyIsam与InnoDB的区别


MyISAM

InnoDB

最大存储

256TB

64TB

事务

N

Y

表锁

行锁

MVCC

N

Y

B-TREE

Y

Y

全文索引

N

Y

聚簇索引

N

Y

数据缓存

N

Y

索引缓存

Y

Y

解释:

    <1>事务:多种操作的集合。多会话访问数据库时,每一个操作都会有一个ID,之间互不干扰。假设A在数据库的某张表中有先插入、再删除的操作,操作同时B在查询这张表,那么B查询到的结果是A插入未删时的数据还是A已经删除的操作?其实当A做插入insert操作时,数据库会自动给该动作分配一个ID,做删除的操作时候回再分配一个ID,且后面操作的ID大于签名操作的ID。如果B的查询操作ID位于A的插入之后,删除之前,那么B查询到的就是A在insert后的结果,delete之前的结果

Ainsert=10,Adelete=20,Bselect=15,此时B可以查到A在insert的结果,查询不到A的delete后的结果。

    <2>锁:表锁:锁的动作是对整个表上锁,上锁后其他用户不得访问读写

    行锁:锁的动作是针对某一行上锁

    <3>脏数据:事务过程中还没有结束完的数据,比如说刚才说的A在insert和delete之间未完成的数据

    <4>MVCC:多版本并发控制机制

(2)存储引擎特定

<1>MyISAM特点:

不支持事务

表级锁定

读写相互阻塞,写入不能读,读时不能写

只缓存索引

不支持外键约束

不支持聚簇索引

读取数据较快,占用资源较少

不支持MVCC(多版本并发控制机制)高并发

崩溃恢复性较差

MySQL5.5.5前默认的数据库引擎

<2>适用场景:只读(或者写较少)、表较小(可以接受长时间进行修复操作)

<3>MyISAM引擎文件:

tbl_name.frm: 表格式定义

tbl_name.MYD: 数据文件

tbl_name.MYI: 索引文件

<4>InnoDb引擎特点

行级锁

支持事务,适合处理大量短期事务

读写阻塞与事务隔离级别相关

可缓存数据和索引

支持聚簇索引

崩溃恢复性更好

支持MVCC高并发

从MySQL5.5后支持全文索引

从MySQL5.5.5开始为默认的数据库引擎

<5>InnoDB引擎下,建议修改/etc/my.cnf,在[mysqld]下添加defaults-storage-engine=INNODB和innodb-file-per-table,否则所有InnoDB表的数据和索引放置于同一个表空间中image.png

设置好后从此之后新建的数据库都将数据文件和表格式定义分开存放

数据文件(存储数据和索引):tb_name.ibd,表格式定义:tb_name.frm

2、其它存储引擎

(1)Performance_Schema:Performance_Schema数据库

(2)Memory :将所有数据存储在RAM中,以便在需要快速查找参考和其他类似数据的环境中进行快速访问。适用存放临时数据。引擎以前被称为HEAP引擎

(3)MRG_MyISAM:使MySQL DBA或开发人员能够对一系列相同的MyISAM表进行逻辑分组,并将它们作为一个对象引用。适用于VLDB(Very Large Data Base)环境,如数据仓库

(4)Archive :为存储和检索大量很少参考的存档或安全审核信息,只支持SELECT和INSERT操作;支持行级锁和专用缓存区

(5)Federated联合:用于访问其它远程MySQL服务器一个代理,它通过创建一个到远程MySQL服务器的客户端连接,并将查询传输到远程服务器执行,而后完成数据存取,提供链接单独MySQL服务器的能力,以便从多个物理服务器创建一个逻辑数据库。非常适合分布式或数据集市环境

(6)BDB:可替代InnoDB的事务引擎,支持COMMIT、ROLLBACK和其他事务特性

(7)Cluster/NDB:MySQL的簇式数据库引擎,尤其适合于具有高性能查找要求的应用程序,这类查找需求还要求具有最高的正常工作时间和可用性

(8)CSV:CSV存储引擎使用逗号分隔值格式将数据存储在文本文件中。可以使用CSV引擎以CSV格式导入和导出其他软件和应用程序之间的数据交换

(9)BLACKHOLE :黑洞存储引擎接受但不存储数据,检索总是返回一个空集。该功能可用于分布式数据库设计,数据自动复制,但不是本地存储

(10)example:“stub”引擎,它什么都不做。可以使用此引擎创建表,但不能将数据存储在其中或从中检索。目的是作为例子来说明如何开始编写新的存储引擎

3、MariaDB支持的其它存储引擎:OQGraph、SphinxSE、TokuDB、Cassandra、CONNECT、SQUENCE

4、管理存储引擎

(1)查看库中所有表使用的存储引擎

    Show table status from db_name;

(2)查看库中指定表的存储引擎

    show table status like ' tb_name';

    show create table tb_name;

(3)设置表的存储引擎:

    CREATE TABLE tb_name(... ) ENGINE=InnoDB;

    ALTER TABLE tb_nameENGINE=InnoDB;

(4)查看引擎

    SHOW ENGINES;

5、MySQL中的系统数据库

(1)mysql数据库:mysql的核心数据库,类似于sql server中负责存储数据库的用户、权限设置、关键字等mysql自己需要使用的控制和管理信息

(2)performance_schema:mysql 5.5开始新怎的数据库,主要用于收集数据库服务器性能参数,库里表的存储引擎均为performance_schema,用户不能创建存储引擎为performance_schema的表

(3)information_schema数据库:mysql 5.0之后产生的,一个虚拟数据库,物理上并不存在。提供了访问数据库元数据的方式,即数据的数据。

6、服务器配置

(1)mysqld选项,服务器系统变量和服务器状态变量,在两个官方网址中查询是服务器变量还是服务器选项

https://dev.mysql.com/doc/refman/5.7/en/mysqld-option-tables.html

https://mariadb.com/kb/en/library/full-list-of-mariadb-options-system-and-status-variables/

(2)服务器系统变量:分全局和会话两种

(3)服务器状态变量:分全局和会话两种

(4)获取运行中的mysql进程使用各服务器参数及其值

进入数据库输入SQL语句

SHOW GLOBAL VARIABLES;

SHOW [SESSION] VARIABLES;image.png

      (5)设置服务器选项方法:

<1>在命令行中设置./mysqld_safe --skip-name-resolve=1;

<2>在配置文件my.cnf中添加skip_name_resolve=1,避免IP被反向解析为名字,建议添加此项

(6)修改全局变量:仅对修改后新创建的会话有效;对已经建立的会话无效

    mysql> SET GLOBAL system_var_name=value;

    mysql> SET @@global.system_var_name=value;

(7)修改会话变量:

    mysql> SET [SESSION] system_var_name=value;

    mysql> SET @@[session.]system_var_name=value;

(8)状态变量(只读):用于保存mysqld运行中的统计数据的变量,不可更改

    mysql> SHOW GLOBAL STATUS;

    mysql> SHOW [SESSION] STATUS;

注意:

(1)有些既是服务器变量,又是服务器选项,比如说--binlog-cacho-size为选项,但也有binlog_cache_size的变量

(2)当修改变量时用SET [GLOBAL] VARNAME=value作为修改,用show variables like ' ';查询,该变量修改后会在重启后消失,而且变量不支持加入配置文件中。选项的修改可以直接将该选项放入/etc/my.cnf下的[mysqld],该修改为永久保存。查找是服务器变量还是服务器选项去刚给的官网网址可以查找

(3)查询变量show [global] variables like '...%';

    查询状态变量show [global] status like '...%';,不可更改,只读

7、服务器变量SQL_MODE

(1)SQL_MODE:对其设置可以完成一些约束检查的工作,可分别进行全局的设置或者当前会话的设置

(2)开启方式:SET SQL_MODE='traditional',加上global对全局设置,不加global对当前会话设置

(3)常见MODE

<1>NO_AUTO_CREATE_USER:禁止GRANT创建密码为空的用户

<2>NO_ZERO_DATE:在严格模式,不允许使用‘0000-00-00’的时间

<3>ONLY_FULL_GROUP_BY:对于GROUP BY分组操作,如果SELECT的字段没有在分组GROUP BY中存在会认为这个SQL语句是不合法的

<4>NO_BACKSLASH_ESCAPES:反斜杠\作为普通字符而非转义字符

<5>PIPES_AS_CONCAT:将||视为连接操作符而非“或运算符”

8、查询缓存

(1)查询先看是否有查询缓存,如果有将直接显示缓存,加快了速度。由于查询缓存运用了哈希运算,因此如果想要引用查询缓存,SQL语句使用需要与在查询缓存中的SQL语句一模一样,甚至大小写一致

(2)哪些查询可能不会被缓存

<1>查询语句中加了SQL_NO_CACHE参数

<2>查询语句中含有获得值的函数,包含自定义函数,如:NOW()

CURDATE()、GET_LOCK()、RAND()、CONVERT_TZ()等

<3>对系统数据库的查询:mysql、information_schema查询语句中使用SESSION级别变量或存储过程中的局部变量

<4>查询语句中使用了LOCK IN SHARE MODE、FOR UPDATE的语句,查询语句中类似SELECT …INTO 导出数据的语句

<5>对临时表的查询操作;存在警告信息的查询语句;不涉及任何表或视图的查询语句;某用户只有列级别权限的查询语句

<6>事务隔离级别为Serializable时,所有查询语句都不能缓存

(3)查询服务器相关变量

show variables like 'query_cache%';image.png

<1>query_cache_min_res_unit: 查询缓存中内存块的最小分配单位,默认4k,较小值会减少浪费,但会导致更频繁的内存分配操作,较大值会带来浪费,会导致碎片过多,内存不足

<2>query_cache_limit:单个查询结果能缓存的最大值,默认为1M,对于查询结果过大而无法缓存的语句,建议使用SQL_NO_CACHE

<3>query_cache_size:查询缓存总共可用的内存空间;单位字节,必须是1024的整数倍,最小值40KB,低于此值有警报

<4>query_cache_wlock_invalidate:如果某表被其它的会话锁定,是否仍然可以从查询缓存中返回结果,默认值为OFF,表示可以在表被其它会话锁定的场景中继续从缓存返回数据;ON则表示不允许

<5>query_cache_type: 是否开启缓存功能,取值为ON, OFF, DEMAND,当query_cache_type的值为ON或1时,查询缓存功能打开,SELECT的结果符合缓存条件即会缓存,显式指定SQL_NO_CACHE,不予缓存,此为默认值;当query_cache_type的值为DEMAND或2时,查询缓存功能按需进行,显式指定SQL_CACHE的SELECT语句才会缓存;其它均不予缓存

注意:以上为服务器变量,设置时候是SET [GLOBAL] VARNAME=value;

9、优化查询缓存

image.png

10、查询缓存

查询缓存相关的状态变量:SHOW GLOBAL STATUS LIKE ‘Qcache%';

(1)Qcache_free_blocks:处于空闲状态Query Cache中内存Block 数

(2)Qcache_total_blocks:Query Cache 中总Block ,当Qcache_free_blocks相对此值较大时,可能用内存碎片,执行FLUSH QUERY CACHE清理碎片

(3)Qcache_free_memory:处于空闲状态的Query Cache 内存总量

(4)Qcache_hits:Query Cache 命中次数,比如输入同一个SQL查询语句两次,该记录会加1,两次输入的SQL语句大小必须一致

(5)Qcache_inserts:向Query Cache 中插入新的Query Cache 的次数,即没有命中的次数

(6)Qcache_lowmem_prunes:0记录有多少条查询因为内存不足而被移除出查询缓存

(7)Qcache_not_cached:没有被Cache 的SQL 数,包括无法被Cache 的SQL 以及由于query_cache_type设置的不会被Cache 的SQL语句,比如select now()输入后,该记录会加1

(8)Qcache_queries_in_cache:在Query Cache 中的SQL 数量image.png

由此可以得出命中率和内存使用率估算:

(1)查询缓存中内存块的最小分配单位query_cache_min_res_unit:(query_cache_size-Qcache_free_memory) / Qcache_queries_in_cache

(2)查询缓存命中率:Qcache_hits/ ( Qcache_hits+ Qcache_inserts) * 100%

(3)查询缓存内存使用率:(query_cache_size–qcache_free_memory) / query_cache_size* 100%

11、InnoDB存储引擎

(1)InnoDB存储引擎的缓冲池:通常InnoDB存储引擎缓冲池的命中不应该小于99%

(2)查看相关状态变量:只读

show global status like 'innodb%read%'\G

<1>Innodb_buffer_pool_reads: 表示从物理磁盘读取页的次数

<2>Innodb_buffer_pool_read_ahead: 预读的次数

<3>Innodb_buffer_pool_read_ahead_evicted: 预读页,但是没有读取就从缓冲池中被替换的页数量,一般用来判断预读的效率

<4>Innodb_buffer_pool_read_requests: 从缓冲池中读取页次数

<5>Innodb_data_read: 总共读入的字节数

<6>Innodb_data_reads: 发起读取请求的次数,每次读取可能需要读取多个页

12、索引

(1)索引是特殊结构:定义在查找时作为查找的字段

(2)索引实现基于存储引擎

(3)优点:

<1>索引可以降低服务需要扫描的数据量,减少了IO次数

<2>索引可以帮助服务器避免排序和使用临时表

<3>索引可以帮助将随机IO转为顺序IO

(4)缺点:

<1>占用额外空间,影响插入速度,不过对于具有大量查询需求的数据库是值得的

<2>数据库发生变化,索引也需要更新

(5)索引类型

<1>B-TREE(念作B树)、B+ TREE、HASH、R TREE

<2>聚簇(集)索引、非聚簇索引:数据和索引是否存储在一起

聚集索引:数据和索引放在一起,InnoDB

非聚集索引:数据和索引分离放置,MyISAM

<3>主键索引、二级(辅助)索引

主键索引:索引的排列次序和数据在磁盘上的排列次序是一致的

二级索引:利用唯一键建立索引

<4>稠密索引、稀疏索引:是否索引了每一个数据项

稠密索引:索引存放了每个数据项

稀疏索引:索引存放了部分数据项

<5>简单索引、组合索引

左前缀索引:取前面的字符做索引

覆盖索引:从索引中即可取出要查询的数据,性能高

(6)B-TREE,平衡树,balanced treeimage.png

(7)B+TREE,比B-TREE稳定image.png

<1>可以使用B+Tree索引的查询类型:

全值匹配:精确所有索引列,如:姓wang,名xiaochun,年龄30

匹配最左前缀:即只使用索引的第一列,如:姓wang

匹配列前缀:只匹配一列值开头部分,如:姓以w开头的

匹配范围值:如:姓ma和姓wang之间

精确匹配某一列并范围匹配另一列:如:姓wang,名以x开头的

只访问索引的查询

<2>B+Tree索引的限制:

如不从最左列开始,则无法使用索引,如:查找名为xiaochun,或姓为g结尾

不能跳过索引中的列:如:查找姓wang,年龄30的,只能使用索引第一列

如果查询中某个列是为范围查询,那么其右侧的列都无法再使用索引:如:姓wang,名x%,年龄30,只能利用姓和名上面的索引

<3>特别提示:

索引列的顺序和查询语句的写法应相匹配,才能更好的利用索引

为优化性能,可能需要针对相同的列但顺序不同创建不同的索引来满足不同类型的查询需求

(8)Hash索引

<1>Hash索引:基于哈希表实现,基于哈希表实现,只有精确匹配索引中的所有列的查询才有效,索引自身只存储索引列对应的哈希值和数据指针,索引结构紧凑,查询性能好

<2>Memory存储引擎支持显式hash索引,InnoDB和MyISAM存储引擎不支持

<3>适用场景:只支持等值比较查询,包括=, <=>, IN()

<4>不适合使用hash索引的场景

不适用于顺序查询:索引存储顺序的不是值的顺序

不支持模糊匹配

不支持范围查询

不支持部分索引列匹配查找:如A,B列索引,只查询A列索引无效

(9)地理空间索引( Geospatial indexing)

MyISAM支持地理空间索引,可以使用任意维度组合查询,使用特有的函数访问,常用于做地理存储存储,使用不多

InnoDB从MySQL5.7后开始支持

(10)全文索引

在文本中查找关键词,而不是直接比较索引中的值,类似搜索引擎

InnoDB从MySQL5.6后开始支持

(11)冗余和重复索引:

冗余索引:(A),(A,B),比如说有了idx_name_age建立的符合索引,此时再有name或者age的索引,name或者age就是冗余索引

重复索引:已经有索引,再次建立索引

(12)索引优化策略:

<1>独立地使用列:尽量避免其参与运算,独立的列指索引列不能是表达式的一部分,也不能是函数的参数,在where条件中,始终将索引列单独放在比较符号的一侧

<2>左前缀索引:构建指定索引字段的左侧的字符数,要通过索引选择性来评估,比如说某个表格name字段定义时候是CHAR(50),但name字段中的所有值按照CHAR(10)的规格就可以使用,此时定义name索引时可以更改name字段字符数,CREATE INDEX idx_name ON tbl_name(name(10));

索引选择性:不重复的索引值和数据表的记录总数的比值

<3>多列索引:AND操作时更适合使用多列索引,而非为每个列创建单独的索引,查询语句的where从句中用and连接两个加了索引的字段

<4>选择合适的索引列顺序:无排序和分组时,将选择性最高放左侧 

13、管理索引

(1)创建索引:

CREATE INDEX index_name ON tbl_name (index_col_name[(length)],...);

help CREATE INDEX;

(2)索引的使用:

SELECT ... WHERE 字符(加索引的字段) { like | in | = ...};

(3)删除索引:

DROP INDEX index_name ON tbl_name;

(4)查看索引:

SHOW INDEXES FROM [db_name.]tbl_name;

(5)优化表空间:

OPTIMIZE TABLE tb_name;,当索引建立后长时间不用

(6)查看索引的使用

SET GLOBAL userstat=1;

SHOW INDEX_STATISTICS;

示例:现有一存储过程,可以实现建立99999个用户id、name、age的表格image.png

之后mysql DB < FILE.sql,进入数据库调用call protestlog,产生数据表如图

image.png

共有99999条这样的记录,现在我们开始示例索引image.png

利用索引查询和不利用索引查询image.png

删除索引

image.png

建立复合索引

image.png

14、索引优化建议

(1)只要列中含有NULL值,就最好不要在此例设置索引,复合索引如果有NULL值,此列在使用时也不会使用索引

(2)尽量使用短索引,如果可以,应该制定一个前缀长度

(3)对于经常在where子句使用的列,最好设置索引

(4)对于有多个列where或者order by子句,应该建立复合索引

(5)对于like语句,以%或者‘-’开头的不会使用索引,以%结尾会使用索引,索引使用禁止使用like '%...'或者'%...%',只允许'...%'的形式

(6)尽量不要在列上进行运算(函数操作和表达式操作)

(7)尽量不要使用not in和<、>操作

15、SQL语句性能优化

(1)查询时,能不要*就不用*,尽量写全字段名

(2)大部分情况连接效率远大于子查询

(3)多表连接时,尽量小表驱动大表,即小表 join 大表

(4)在有大量记录的表分页时使用limit

(5)对于经常使用的查询,可以开启缓存

(6)多使用explain和profile分析查询语句

(7)查看慢查询日志,找出执行时间长的sql语句优化

16、EXPLAIN

通过EXPLAIN来分析索引的有效性

(1)用法:EXPLAIN SELECT 从句

(2)id: 当前查询语句中,每个SELECT语句的编号

复杂类型的查询有三种:

简单子查询

用于FROM中的子查询

联合查询:UNION

注意:UNION查询的分析结果会出现一个额外匿名临时表

(3)select_type:

简单查询为SIMPLE

复杂查询:

SUBQUERY 简单子查询

PRIMARY 最外面的SELECT

DERIVED 用于FROM中的子查询

UNION UNION语句的第一个之后的SELECT语句

UNION RESULT 匿名临时表

(4)table:SELECT语句关联到的表

(5)type:关联类型或访问类型,即MySQL决定的如何去查询表中的行的方式,以下顺序,性能从低到高

<1>ALL: 全表扫描

<2>index:根据索引的次序进行全表扫描;如果在Extra列出现“Using index”表示了使用覆盖索引,而非全表扫描

<3>range:有范围限制的根据索引实现范围扫描;扫描位置始于索引中的某一点,结束于另一点

<4>ref: 根据索引返回表中匹配某单个值的所有行

<5>eq_ref:仅返回一个行,但与需要额外与某个参考值做比较

<6>const, system: 直接返回单个行

(6)possible_keys:查询可能会用到的索引

(7)key: 查询中使用到的索引

(8)key_len: 在索引使用的字节数

(9)ref: 在利用key字段所表示的索引完成查询时所用的列或某常量值

(10)rows:MySQL估计为找所有的目标行而需要读取的行数

(11)Extra:额外信息

Using index:MySQL将会使用覆盖索引,以避免访问表

Using where:MySQL服务器将在存储引擎检索后,再进行一次过滤

Using temporary:MySQL对结果排序时会使用临时表

Using filesort:对结果使用一个外部索引排序

示例

image.png

出现黄字情况possible_keys有值,但key为NULL


猜你喜欢

转载自blog.51cto.com/13873498/2299092