MySQL(1) - 基础
参考资料:
http://www.jianshu.com/p/91e3af27743f
一、MySQL介绍以及安装
1.1 MySQL介绍
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区进行维护,采用GPL授权许可。Oracle在收购MySQL之后,有将MySQL闭源的潜在可能。Google Facebook等在大约2年前基本完全弃用了MySQL转向了MariaDB,而在较新的Linux发行版,例如CentOS7中也把MySQL改为了MariaDB。
MariaDB由MySQL的创始人麦格尔主导研发,直到5.5版本,MariaDB均按照MySQL的版本,而从2012年开始,不再使用MySQL的版本号,10.0.x均以5.5版为基础,进行新特性的开发。
MariaDB的API完全兼容MySQL,因此之后的MySQL均以MariaDB为准使用。
MySQL的架构如下图所示:
MySQL 组件:
- Connetcion Pool:MySQL的线程池,负责客户端连接的维护,包含连接密码认证,线程重用,连接数控制,内存检测以及连接线程的缓存功能。
- SQL Interface:SQL接口,提供了MySQL的大多数逻辑组件,类似Linux的Shell,包含了DML,DDL,视图,过程等等MySQL中常用的组件。
- Parser:MySQL的Query Translation,将SQL接口接收的语句转换为MySQL内部接口的语句,并提供了权限验证功能。
- Optimizer: SQL语句在查询之前会使用查询优化器对其进行优化,并记录到统计数据中。
- Caches & Buffers: MySQL自我管理的缓存和Buffer
- Pluggable Storeage Engines: MySQL支持插件式的存储引擎,存储引擎是MySQL和文件系统打交道的具体系统。
- File system: 外部的文件系统
- Files & logs: MySQL的物理视图,即MySQL在文件系统中的具体文件,例如事务中的Redo日志,Undo日志,Data数据文件,Index索引文件,错误日志,慢查询日志等等。
MySQL的设计是一个单进程多线程的架构设计,通过线程池来进行管理的每一个用户连接的设计,因此从一开始MySQL对多核心系统的利用就欠佳,直到MySQL5.5开始大规模企业化之后,一直致力于MySQL在多核系统中的表现。但是MySQL在每一个连接中依旧只能利用到单核心,即你的SQL语句哪怕再复杂,也只能用一个CPU去处理。
由于MySQL只有1个进程,而单个进程在Linux系统上能使用的内存是有限制的,因此MySQL没有其他选择,必须使用64位的操作系统,否则内存的限制将是一个无法解决的瓶颈。
1.2 安装
MaraiDB的安装方式多种多样,Centos7自带yum源中的就是MariaDB
yum install -y jemalloc jemalloc-devel #依赖于其中的一个共享库文件 安装方式一般有三种: (1) rpm: OS: 操作系统的yum源中自带 官方: 官网上下载rpm包并且进行安装 (2) 源码包: 需要自己编译,除非有特定需求,不建议这么做 (3) 通用二进制格式的程序包: 下面以CentOS7为例,使用通用二进制格式的程序包安装:准备admin用户mysql,mysql组 (1) 准备数据目录; 以/mydata/data目录为例;(最好是创建一个新的分区专门存放数据) chown -R mysql.mysql /mydata/data/ (2) 安装配置mariadb # useradd -r mysql # tar xf mariadb-VERSION.tar.xz -C /usr/local # cd /usr/local # ln -sv mariadb-VERSION mysql # cd /usr/local/mysql # chown -R root:mysql ./* # scripts/mysql_install_db --user=mysql -datadir=/mydata/data 初始化数据,不能使用绝对路径,只能在这个位置 # cp support-files/mysql.server /etc/init.d/mysqld # chkconfig --add mysqld (3) 提供配置文件 ini格式的配置文件;各程序均可通过此配置文件获取配置信息; [program_name] OS Vendor提供mariadb rpm包安装的服务的配置文件查找次序: /etc/mysql/my.cnf --> /etc/my.cnf --> --default-extra-file=/PATH/TO/CONF_FILE --> ~/.my.cnf 通用二进制格式安装的服务程序其配置文件查找次序: /etc/my.cnf --> /etc/mysql/my.cnf --> --default-extra-file=/PATH/TO/CONF_FILE --> ~/.my.cnf 获取其读取次序的方法: mysqld --verbose --help | less # cp support-files/my-large.cnf /etc/my.cnf 添加三个选项: datadir = /mydata/data innodb_file_per_table = ON skip-name-resolve = ON (4) 启动服务 # service mysqld start 安装完成后,使用mysql_secure_installation进行固化操作: root密码 禁止root远程登录 移除匿名用户
二、MySQL架构
2.1 MySQL逻辑架构
上图为MySQL的逻辑架构图,
第一层架构非常容易理解,大多数基于网络socket进行通信的工具或者服务都有类似的架构。比如连接处理、授权认证、安全等等。
第二层是比较有意思的部分,大多数MySQL的核心服务都在这一层,包括查询解析、分析、优化、缓存以及所有的内置函数(例如日期 时间 数学 加密),所有跨存储引擎(即和存储引擎无关)的功能都实现这一层:存储过程、触发器、视图等。
第三层包含了存储引擎。存储引擎负责MySQL中数据的存储和提取。和GUN/Linux中的各种文件系统一样,每个存储引擎都有它的优势和劣势。服务器通过API与存储引擎进行通信,这些接口屏蔽了不同存储引擎的差异。存储引擎API包含了几十个底层函数,用于执行例如"开始一个事务"或者"根据主键提取一行"记录等。存储引擎不会去解析SQL(InnoDb是一个例外,它会解析外键定义,因为MySQL服务器本身没有实现该功能),不同存储引擎之间不会相互通信,而只是简单地响应上层服务器的请求。
2.2 连接管理和安全性
每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在单独的线程中去执行,该线程只能轮流在某个CPU核心或者CPU中运行。服务器会负责缓存线程,因为不需要为每一个连接创建或者销毁线程。(MySQL5.5或者更新的版本提供了一个API:支持线程池Thread-Pooling插件,可以使用池中的少量线程来服务大量的连接)
当客户端(应用)连接到MySQL服务器时,服务器需要对其进行认证。认证基于用户名、原始主机信息和密码。如果使用了安全套接字(SSL,还支持证书)。一旦连接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限,例如,是否允许客户端是否对world数据库的Country表执行SELECT语句。
2.3 优化和执行
MySQL会解析查询,并创建内部数据结构(解析树),然后对其各种优化、包括重写查询,决定表的读取顺序,以及选择合适的索引等。用户可以通过特殊的关键字(hint)去提示优化器,影响它的决策 ,
也可以使用explain解析优化过程的各个因数,使用户可以知道服务器如何决策,并提供一个参考基准,以便于用户可以重构查询和schema,修改相关配置,使得应用尽可能高效运行。
优化器不关心表使用的存储引擎是什么,但是存储引擎对性能的影响又很重要。优化器会请求存储引擎提供容量或者某个具体操作的开销信息,以及表数据的统计信息等。例如,某些存储引擎的某种索引特性等。
对于SELECT 语句,在解析查询之前,服务器会先检查查询缓存,如果有缓存直接从缓存中返回。
2.4 并发控制
1. 读写锁:
读锁:共享锁
写锁:排他锁
就是一般的读写锁:读锁与读锁不互斥,写锁比读锁拥有更高的优先级。
2. 锁粒度:
一种提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源,可是问题是加锁也需要消耗资源,粒度越小的锁越需要管理,获取锁,检查锁是否删除,释放等等。
所谓的锁策略:就是在锁的开销和数据的安全性之间取得平衡。
MySQL提供了多种选择,每种存储引擎可以实现自己的锁策略和锁粒度。在存储引擎的设计中,锁管理是一个非常重要的决定,下面介绍2种最重要的锁策略。
表锁(table lock):
最基本的锁策略,并且是开销最小的。尽管存储引擎可以自己管理锁,MySQL本身还是会听各种机制来实现目的。例如,服务器会为诸如ALTER TABLE这样的语句使用表锁,而忽略存储引擎的锁机制
行级别锁(row lock):
行级锁可以最大程度地支持并发处理(同时也带来最大的锁开销)。众所周知,在InnoDB和XtraDB,以及其他一些存储引擎中实现了行级锁。行级锁只在存储引擎层实现,而MySQL服务器层没有实现。
而从用户的角度看又可以分为显示锁,用户可以显示请求调用的锁称为显示锁,是表级锁,而隐式锁则是由存储引擎自动施加的锁,用户不可见,由存储引擎决定。
从锁的粒度来看分为表级锁和行级锁,锁的粒度精细,实现越复杂,因此锁的使用策略就是在粒度和控制上实现一种平衡。
2.5 事务
事务: A transaction is a group of SQL queries that one threated atomically, as a single unit of work.
Atomicity:A transaction must function as a single indivisible unit of work so that the entire transaction is either applied or rolled back
Consistency:The database should always move from one consistent state to the next
Isolation:The results of a transaction are usually invisble to the other transactions until the transaction is complete.
Durability:Once commited, a transaciton's changes are permanent.
tx_isolation: 隔离级别
可以使用命令show variables like 'tx_%';查看事务隔离级别tx_isolation
事务隔离级别:(Isolation Levels)
READ-UNCOMMITED:Transactions can view the results of uncommited transactions
READ-COMMITED:A transaction will see only those changes made by transactions that were already commited when it began, and its change won't be visible to other unitl it has commited
REPEATABLE-READ:It gurantees that any rows a transaction read will "look the same" in subsequent reads within the same transaction, but in theory it still allows another tricky problem: phantom reads.
SERIALIZABLE:one by one.
死锁:
看上面的2个事务,如果凑巧,2个事务同时执行了第一条SQL语句,更新了一行数据,同时也锁定了该行数据,接着2个事务去尝试第二条SQL语句,发现被对方锁定,跟Java代码中多线程顺序死锁几乎一样,此时需要外部因素介入才能解除死锁。
为了解决这种问题,数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,比如InnoDB存储引擎,越能检测到死锁的循环依赖,并立即返回一个错误,这种方式非常有效,否则出现超慢查询。
还有一种解决方式,当查询时达到等待超时的设定之后放弃锁清秋,这种方式不太友好,而InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚。
前面说过,锁的行为和顺序和存储引擎相关的。也就是说,有些死锁是因为真正的数据冲突,有些则是这个存储引擎的问题。
2.5.1 事务日志
事务日志可以帮助事务的效率。使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘。事务日志采用的是追加的方式(实际上这种日志追加方式非常常见),因此写日志的方式是一小块区域内的顺序I/O,而不是随机IO,随机IO需要在磁盘上的多个地方移动磁头,所以采用事务日志的方式相对要快的多,注意这里是指在机械硬盘上会快的多,固态硬盘...。事务日志持久后,内存中的数据可以慢慢地刷回到磁盘。目前大多数存储引擎都是这样实现的,我们通常称之为预写式日志(Write-Ahead Logging),修改数据需要写2次磁盘。
如果数据的修改已经记录到事务日志并持久化,但数据本身还没有写回磁盘,此时系统崩溃,存储引擎在重启时能够恢复这部分的数据。具体的恢复方式视存储引擎而定。
InnoDB中查看事务日志
innodb_log_file_size 文件大小
innodb_log_files_in_group 单组文件个数
innodb_log_group_home_dir 文件home目录
可以在MySQL初始化时在配置文件中指定。注意文件大小要适量。
2.5.2 MySQL中的事务
MySQL中提供了2种事务型的存储引擎:InnoDB和NDB Cluster。另外还有一些第三方的存储引擎也支持事务,比较知名的包括XtraDB和PBXT。
MySQL服务器层不管理事务,事务由下层的存储引擎实现的。所以在同一个事务中,使用多种存储引擎是不可靠的~
如果在事务中混合使用了事务型(InnoDB)和非事务型(MyISAM),在正常提交的情况下不会有问题,可是如果要回滚,非事务型的不能回滚,事务的结果将无法确定。
显示锁定和隐式锁定:
在InnoDB引擎中采用的是二阶段锁定协议(two-phase lockiing protocol)。在事务执行过程中,随时都可以执行锁定,锁只有在COMMIT或者ROLLBACK的时候才会释放,并且锁是在同一时刻被释放。前面描述的都是隐式锁定,InnoDB会根据隔离级别在需要的时候自动加锁。另外InnoDB也支持显式锁定,不过这些语句不属于SQL规范
SELECT clase [FOR UPDATE] [WITH READ LOACK]
MySQL也支持LOCK TABLES和UNLOCK TABLES语句,这是在服务层实现的,和存储引擎无关。它们有自己的用途,但是并不能代替事务处理。如果应用需要用到事务,还是应该选择事务型存储引擎。
Syntax: LOCK TABLES tbl_name [[AS] alias] lock_type [, tbl_name [[AS] alias] lock_type] ... lock_type: READ [LOCAL] | [LOW_PRIORITY] WRITE UNLOCK TABLES
经常可以发现,应用已经将表从MyISAM转换到InnoDB,但还是显示地使用LOCK TABLES语句。这不但没有必要,还会严重影响性能,实际上InnoDB的行级锁工作的更好。
LOCK TABLES和事务之间相互影响的话,情况会变的非常复杂,在某些MySQL版本中甚至会产生无法预料的结果。因此,建议出了事务中禁用了AUTOCOMMIT,可以使用LOCK TABLES外,其他任何时刻都不要显式的执行LOCK TABLES,不管使用的是什么存储引擎!
2.5.3 多版本并发控制
MySQL中的大所数事务型存储引擎实现的都不是简单的行级锁。基于提升性能的考虑,同时实现了MVVC(多版本并发控制)。不仅仅是MySQL,包括Oracle,PostgreSQL等其他数据库系统也都实现了MVCC,但各自实现的机制不尽相同,因为MVCC没有一个统一的实现标准。
可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,incident开销更低。虽然实现机制不同,大都实现了非阻塞的读写操作,写操作也只需要锁定必要的行。
MVCC的实现,是通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长的时间,每个事物看到的数据都是一致的。根据事物开始的时间不同,每个事务对同一张表,同一个时刻看到的数据可能是不一样的。
典型的实现方式:乐观(optimistic)并发控制和悲观(pessimistic)并发机制。下面我们通过InnoDB的简化版行为来说明MVCC是如何工作的
InnoDB的MVCC,是通过在每行记录后面保存2个隐藏的列来实现的。这2个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。当然存储的并不是实际时间,而是系统版本号(system version number)。每开始一个新的事务,系统的版本号递增。
事务开始时刻的系统版本号会做为事务的版本号,用来和查询每行记录的版本号对比。下面看在REPEATABLE READ隔离级别下,MVCC具体是如何操作的。
SELECT:
InnoDB根据以下条件检查每行记录:行版本号<事务版本号<删除版本号
a. InnoDB只查找版本号早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,是事务开始之前已经存在的或者是事务自身插入或者修改的。
b. 行的删除版本要么未定义,要么大于当前事务版本号。这样可以保证事务读取到的行,在事务开始之前未被删除。
符合2个条件的记录,才能被作为查询结果。
INSERT
InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
DELETE
InnoDB为删除的每一行保存当前系统的版本号作为行删除标识。
UPDATE
没更新一条记录,保存当前系统的版本号为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
保存着2个系统版本号,使得大多数读操作可以不用加锁。这样设计使得读的性能更好,并且保证只会读取到符合要求的行。不足的是每行记录都需要额外的空间,典型用空间换取时间。
注意:MVCC只有在REPEATABLE READ和READ COMMITED2个隔离级别下工作。其他2个级别不能使用MVVC。READ UNCOMMITED总是读取最新的行,而SERIALIZABLE总是对所有行为加锁。
三、存储引擎
存储引擎说白了就是如何在文件系统上存储数据、建立索引、更新、查询等等,是MySQL的真正实现方案,MySQL是采用一种插件式的存储引擎管理方案,可以通过show engines查看MySQL支持的所有存储引擎,可以使用show table status like [table_name]的方式来查看表的存储引擎。
(1) InnoDB
在mysql5.5之后,InnoDB就被指定为是默认的存储引擎,而MariaDB使用percona提供的XtraDB引擎作为InnoDB的增强版,非常适合大量的短期事务。
为了改善InnoDB的性能,Oracle投入了大量的资源,额外的贡献者也很有帮助。之前的版本在超过4核CPU的系统中InnoDB的表现不佳,现在已经可以很好的扩展到24核,32核系统中。
InnoDB的数据存储在表空间中:
根据配置有2种情况:
第一种所有的InnoDB表中的数据和索引放置于同一表空间中,而表空间文件会放放置datadir指定的目录中,数据文件大致上为ibddata1,ibddata2.....
第二种更为常用,每个表使用独自的表空间,需要在配置文件或者启动参数中设置innodb_file_per_table=ON来启用该功能,此时每个数据文件+索引在tb_name.idb中,表格式定义元数据文件 tb_name.frm,开启这个特性对于后期的扩展是必备条件,例如一个demo的db中存储了一个t1的表,如图所示生成2个文件
- InnoDB采用MVCC来支持高并发,实现了4个事务隔离级别,默认使用REPEATABLE READ,并且通过间隙锁(next-key locking)策略来防止幻读。
- InnoDB的表示基于聚簇索引。聚簇索引往往是主键索引,因此其主键索引查询有很高的性能。不过它的二级索引,即非主键索引中必须包含主键列,因此如果主键列很大,所有的索引都很大。
- InnoDB的行为非常复杂,官方手册中描述的非常清楚。
- 作为事务型的存储引擎,InnoDB可以实现真正的热备。
(2) MyISAM
MySQL自己研发的一个存储引擎,在MariaDB中使用aira作为增强版实现
表格式文件,数据文件,索引文件单独存放,分别是tb_name.frm,tb_name.myd,tb_name.myi
特性:
最大存储能力为256TB
支持全文索引Full Text
只支持表级锁
不支持事务、外键、数据缓存、不支持MVVC
只能手工修复
索引是非聚集索引
支持延迟更新索引
支持表压缩机制
MySQL中其他常见的存储引擎:
csv:将普通的csv作为MySQL使用
MRG_MYISAM:将多个MyISAM表合成为一个虚拟表
BLACKHOLE:黑洞
MMEORY: 内存,支持hash索引,表级别锁
PERFORMANCE_SCHEMA: 伪存储引擎
FEDERTED: 远程MySQL代理
MariaDB中还支持:
OQGraph:
SpinxSE: 可以和spinx集成
TokuDB:海量数据存储
Cassandra:可以和Cassandra集成
...
总结,如何选择存储引擎:
需要事务?InnoDB
需要外键?InnoDB
需要热备?InnoDB
需要Fulltext?MyISAM
四、查询缓存
从磁盘中读数据会产生磁盘IO,因此在读多写少的场景下,可以使用缓存。
MySQL天然支持查询缓存,在某些情况下还是可以用的,比如说单台服务器,多台服务器一般采用专门的缓存服务器比如Memcached,redis等等服务器实现。
这里的关注重点在MySQL本身的查询缓存,MySQL可以对每次查询做hash键,查询的数据为value进行缓存,而这里的查询key需要考略多方面因数:
查询本身
查询的数据库
客户端使用的协议版本。。。
注意: 查询语句任何的不同,哪怕是一个空格,一个大小写都会引起查询缓存的不同,因此所有程序员保持一定的SQL书写风格还是有必要的。
在前面的MySQL架构中描述了查询缓存实现的组件,而InnoDB,最常见的存储引擎是支持查询缓存的。
在实战中,查询缓存也有可能成为并发热点问题,这往往是由于多核竞争引起的,由于计算机的核心数较多,高并发场景下产生的竞争问题,这也是查询缓存的内存大小默认不会太大的原因,默认是16M.
同时要注意到,不是所有的数据都会缓存,比如我查询一个select now(),这完全不能缓存,一般包含以下内容的都不会缓存,比如用户自定一函数,存储过程,自定义变量,临时表,mysql库中的系统表,不确定值等等。
variables中的相关变量有:
query_cache_min_res_unit: 查询缓存中内存块的最小分配单位;
较小值会减少浪费,但会导致更频繁的内存分配操作;
较大值会带来浪费,会导致碎片过多;
query_cache_limit:能够缓存的最大查询结果;
对于有着较大结果的查询语句,建议在SELECT中使用SQL_NO_CACHE
query_cache_size:查询缓存总共可用的内存空间;单位是字节,必须是1024的整数倍;
query_cache_type: ON, OFF, DEMAND
query_cache_wlock_invalidate:如果某表被其它的连接锁定,是否仍然可以从查询缓存中返回结果;默认值为OFF,表示可以在表被其它连接淘宝的场景中继续从缓存返回数据;ON则表示不允许;
上述参数可以用来对查询缓存进行调优,调优流程图如下:
而缓存的命中率可以作为一个参考,注意只是一个参考,因为可能命中率很低,10条语句只有3条,但是如果这3条返回的数据量值得缓存,计算方式是Qcache_hits/(Qcache_hits+Com_select)
以上变量都是variables中的值,而相关变量大概如下:
SHOW GLOBAL STATUS LIKE 'Qcache%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Qcache_free_blocks | 1 | | Qcache_free_memory | 16759688 | | Qcache_hits | 0 | | Qcache_inserts | 0 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 0 | | Qcache_queries_in_cache | 0 | | Qcache_total_blocks | 1 | +-------------------------+----------+
五、 索引简介
说起sql优化,大部分都落实在索引优化上,什么是索引,MySQL不可能在每次查询数据时将磁盘的数据全部加载到内存中,需要利用数据结构加载少量数据集到内存中即可,这部分数据集就是索引。索引的优点大致如下:
索引可以降低服务器查询的io次数
索引可以帮助服务器避免排序和使用临时表
索引可以帮助将随机I/O转换为顺序IO(在硬盘非固态的时候还是有用的)
索引功能主要由存储引擎来实现,不同的引擎可以使用不同的索引结构。
(1) B+树索引
B+树是一种常见的数据结构,是B树的变种,相对于B树,(B树是什么?略),增加了以下特性
1. 所有的关键字存储在叶子节点中
2. 为所有叶子节点增加了一个链指针
B+树是很适合硬盘读写的数据结构。红黑树等虽然也适合用来实现索引,比如JAVA中的Treemap就是红黑树,适合用来在内存中做索引。
这是由于局部性原理和磁盘预读,什么是局部性原理?时间上,data被用到后,之后的时间很可能再次被用到,空间上,data被用到后,附近的数据很可能被用到,这就是局部性,程序使用的数据在空间上和时间上都是比较集中的。由于磁盘的存取速度很慢,比如在机械硬盘物理上的平均寻址时间,由于linux系统不管什么io模型都必须经历的2个阶段(磁盘->内核空间,内核空间->用户空间)等等...,所以MySQL要尽可能的减少IO的存取次数,而B+树就比较合适,B+树内节点都没有data,只有叶子节点上有data,因此每个节点可以存储更多的数据,范围更大,单次IO的数据量更大,可以直接预读,而且由于新增链指针,可以很方便的进行区间查找,即MySQL中where子句中的between操作。
B+树索引在MySQL中有以下要点:
适用于:
精确值匹配,例如="aa"
最左前缀,例如like "Jin%"
范围匹配,例如 < >
精确匹配之后范围匹配,一般精确匹配都在左侧,而范围适合在右侧,且中间不能跳过其他字段
覆盖索引,索引中就包含要返回信息,不需要查找数据
不适用于:
-
- 不是按照索引的最左列开始查找;
- 不能跳过索引中的列;
- 如果查询中的某个列是范围查询, 则其右边的所有列都无法使用索引;比如like, between
- 索引列上使用函数, 或者算数运算
(2) hash 索引
注意:只有Memory存储引擎支持显式hash索引;
适用场景:
只支持等值比较查询,包括=, IN(), <=>;
不适合使用hash索引的场景:
存储的非为值的顺序,因此,不适用于顺序查询;
不支持模糊匹配;
(3) 空间索引(R-Tree):
MyISAM支持空间索引;
(4) 全文索引(FULLTEXT):
在文本中查找关键词;
上面只是常见索引的数据结构以及用法,索引中还存在着许多的细节问题。比如索引要独立使用,不要参与运算,使用函数等等,在选择索引时候使用左前缀考虑左前缀长度等等,多列索引的陷阱等等。
1. 利用索引排序?
由于索引是有序,因此order中的列存在索引时,可以通过索引来排序,否则有可以使用file sorting,这是很不好的。
2. InndoDB中的聚集索引?
聚族(聚集)索引就是叶子节点保存的就是数据本身,索引和数据在一起,一般主键索引才是聚集索引。
优点:数据访问更快,索引扫描无须来回标
缺点:插入速度严重影响插入顺序,比如InnoDB中按照主键逆序;全表扫描会慢;二级索引会变大,且需要二次查找
六、 explain字段说明
注意explain返回不是精确值,只是估计值
id: 当前查询语句中,每个SELECT语句的编号;
注意:UNION查询的分析结果会出现一外额外匿名临时表;
select_type:
简单查询为SIMPLE
复杂查询:
SUBQUERY: 简单子查询;
DERIVED: 用于FROM中的子查询;
UNION:UNION语句的第一个之后的SELECT语句;
UNION RESULT: 匿名临时表;
table:SELECT语句关联到的表;
type:关联类型,或访问类型,即MySQL决定的如何去查询表中的行的方式;
ALL: 全表扫描;
index:根据索引的次序进行全表扫描;如果在Extra列出现“Using index”表示了使用覆盖索引,而非全表扫描;
range:有范围限制的根据索引实现范围扫描;扫描位置始于索引中的某一点,结束于另一点;
ref: 使用了索引,但是可能返回多行根据索引返回表中匹配某单个值的所有行;
eq_ref:仅返回一个行,但与需要额外与某个参考值做比较;
const, system: 直接返回单个行;
possible_keys:查询可能会用到的索引;
key: 查询中使用了的索引;
key_len: 在索引使用的字节数;
ref: 在利用key字段所表示的索引完成查询时所有的列或某常量值;
rows:MySQL估计为找所有的目标行而需要读取的行数;
Extra:额外信息
Using index:MySQL将会使用覆盖索引,以避免访问表;
Using where:MySQL服务器将在存储引擎检索后,再进行一次过滤;
Using temporary:MySQL对结果排序时会使用临时表;
Using filesort:对结果使用一个外部索引排序;