1.视图
本文参考了高性能MySQL
数据库中的视图是一个虚拟表。同真实的表一样,视图包含一系列带有名称的行和列数据。行和列数据来自由定义视图查询所引用的表,并且在引用视图时动态生成。
视图的实现
视图中不存放任何数据,在使用SQL语句访问视图的时候,返回的数据时MySQL从其他表中生成的。视图和表在同一个命名空间,在很多地方对于视图和表是同样对待的。不过也有不同,不能对视图创建触发器,不能使用DROP TABLE命令删除视图。
假设我们创建一个视图:
create view Oceania as
select * from Country where Continent ='Oceania'
with check option;
实现视图最简单的方法是将select语句的结果存放到临时表中。当需要访问视图的时候,直接访问临时表就可以。比如:
select Code, Name from Oceania where Name =‘Australia’;
在实现上述查询时,有两种方式去实现,一种是使用临时表,还有一种是重写含有视图的查询,将视图的定义SQL直接包含进查询的SQL中:
使用临时表算法:
create temporary table TMP_Oceania_123 as
select * from Country where Continent = ‘Oceania’;
select Code, Name from TMP_Oceania_123where Name = ‘Australia’;
使用合并算法的:
select Code, Name from Country
where Continent = ‘Oceania’ and Name = ‘Australia’;
如果可能,会尽可能使用合并算法。下图是这两种算法实现的细节。
如果视图中包含Group by, Distinct, 任何聚合函数,union,子查询等,只要无法在原表记录和视图记录中建立一一映射的场景中,MySQL都会使用临时表算法来实现。可以使用Explain来确定MySQL使用的具体算法。
更新视图
视图可以被更新。只要指定了合适的条件,就可以更新,删除甚至向视图中写入数据。如果视图定义中包含了group by, union, 聚合函数以及其他一些特殊情况,就不能被更新了。更新视图的查询可以是一个关联语句,但是有一个限制,被更新的列必须来自同一个表中。所有使用临时表算法实现的视图都无法被更新。
视图的性能
使用临时表算法实现的视图,在某些时候性能会很糟糕(可能比直接使用等效查询语句要好一点)。MySQL会以递归的方式执行这些视图,先会执行外层查询,即使外层查询优化器将其优化的很好,但是,内外结合的优化却无法做到非常好。如果打算使用视图来提升性能,需要做比较详细的测试。即便是合并算法实现的视图也会有额外的开销,而且使徒的性能很难预测。
视图的限制
视图有很多限制,比如,MySQL不支持物化视图(将视图结果数据存放在一个可以查看的表中,并定期充原始表中刷新数据到这个表中)。也不支持在视图中创建索引。当然,可以通过构建缓存表或者汇总表的办法来模拟。也可以直接使用工具Flexviews来实现这个目的。
2.备份
MySQL并不会保存视图定义的原始SQL语句,所以,如果我们希望简单的修改视图的结果来重新定义,有的人可能会直接使用show create view语句来查看之前的定义,但是该语句查询出来的视图创建语句会让人大失所望,没有格式化,没有注释,没有缩进,基本不可读。
MySQL备份(Backup)与 恢复(Restore)汇总
1.mysqldump
2.mysqlbackup
3.mysqlhotcopy
4.xtrabackup/innobackupex
5.cp
备份备于一切,今天汇总一下常用的几种备份方法,以及恢复的步骤。
在日常工作中,我们会使用mysqldump命令创建sql格式的转储文件来备份数据库。或者我们把数据导出后做数据迁移,主备搭建等操作。mysqldump是一个逻辑备份工具,复制原始的数据库对象定义和表数据产生一组可执行的SQL语句。 默认情况下,生成insert语句,也能生成其它分隔符的输出或XML格式的文件。
shell> mysqldump [arguments] > file_name
我们简单的来看一下日常的用法:
备份所有的数据库:
shell> mysqldump --all-databases > dump.sql (不包含INFORMATION_SCHEMA,performance_schema,sys,如果想要导出的话还要结合--skip-lock-tables和--database一起用)
备份指定的数据库:
shell> mysqldump --databases db1 db2 db3 > dump.sql
当我们只备份一个数据的时候可以省去 --databases 直接写成:mysqldump test > dump.sql 不过有一些细微的差别,如果不加的话,数据库转储输出不包含创建数据库和use语句,所以可以不加这个参数直接导入到其它名字的数据库里
当然我们也可以只备份某个表 :
mysqldump --user [username] --password=[password] [database name] [table name] table_name.sql
了解了简单的一些用法后我们再着重的看一下几个参数:
--master-data 获取备份数据的Binlog位置和Binlog文件名,用于通过备份恢复的实例之间建立复制关系时使用,该参数会默认开启。
--dump-slave 用于在slave上dump数据,建立新的slave。因为我们在使用mysqldump时会锁表,所以大多数情况下,我们的导出操作一般会在只读备库上做,为了获取主库的Relay_Master_Log_File和Exec_Master_Log_Pos,需要用到这个参数,不过这个参数只有在5.7以后的才会有
–no-data, -d 不导出任何数据,只导出数据库表结构
刚刚我们说过在使用mysqldump的时候会锁表,我们来详细的看一下它的锁机制。
我们开两个窗口,在第一个里面执行mysqldump -uroot -pxxxxx --master-data=2 --databases dbname > /tmp/dbnamedate +%F
.sql
然后第二个窗口登陆进去,使用show process的命令可以看到目前dump的session正在执行
SELECT /*!40001 SQL_NO_CACHE */ * FROM table_name; 可以看到这条sql正在以no_cache的模式查询数据。
然后我们在同样的表上执行一下select,发现被阻塞了。光标一直不返回。
一般遇到这种文件,我们会想是不是有锁呢?
为了验证我们查看一下锁的信息,可以发现dump的进程实际上是加了锁的。
我们把具体的general_log打开,然后看一下当时的操作:
4101044 Query FLUSH /*!40101 LOCAL */ TABLES
4101044 Query FLUSH TABLES WITH READ LOCK (关闭所有打开的表,同时对于所有数据库中的表都加一个读锁,直到显示地执行unlock tables,该操作常常用于数据备份的时候。)
4101044 Query SHOW MASTER STATUS(这是因为我用了--master-data=2)
所以这个时候表就会被锁住。
如果我不加--master-data参数(mysqldump -uroot -pxx --databases db > /tmp/dbnamedate +%F
.sql) mysql会显示的对每一张要备份的表执行
LOCK TABLES table_name1
READ,LOCK TABLES table_name2
READ
并且也不会有读的阻塞。
那有没有不锁的方法,其实也是有的,就是使用--single-transaction把备份的操作放在一个事务里去进行
带上--single-transaction参数的mysqldump备份过程:
如果是5.6版本的mysql
在备份之间同样的先FLUSH TABLES WITH READ LOCK,然后设置事务级别SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ,然后开启一个事务START TRANSACTION进行备份,这个时候备份的过程就很意思,它先创建了一个savepoint,然后把数据库里的表依次的进行备份,备份完成了之后又回滚到了之前的savepoint,来保证数据的一致性
如果是5.7版本的mysql
备份前的操作相同,只是没有了savepoint
不过不管是哪个版本,只有InnoDB表是在一个一致性的状态。其它的任何MyISAM表或内存表是没有用的。
mysqldump的优势是可以查看或者编辑十分方便,它也可以灵活性的恢复之前的数据。它也不关心底层的存储引擎,既适用于支持事务的,也适用于不支持事务的表。不过它不能作为一个快速备份大量的数据或可伸缩的解决方案。如果数据库过大,即使备份步骤需要的时间不算太久,但有可能恢复数据的速度也会非常慢,因为它涉及的SQL语句插入磁盘I/O,创建索引等等。
对于大规模的备份和恢复,更合适的做法是物理备份,复制其原始格式的数据文件,可以快速恢复:如果你的表主要是InnoDB表,或者如果你有一个InnoDB和MyISAM表,可以考虑使用MySQL的mysqlbackup命令备份
恢复操作:
先看一下当前的数据:
dbadmin@test 11:10:34>select * from t;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
备份;
mysqldump -uroot -proot@1234 --master-data=1 test >test.sql
模拟增量操作:
dbadmin@test 11:15:17>insert into t values (2);
Query OK, 1 row affected (0.00 sec)
dbadmin@test 11:15:36>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)
模拟误操作:
dbadmin@test 11:15:41>truncate table t;
Query OK, 0 rows affected (0.01 sec)
dbadmin@test 11:16:14>select * from t;
Empty set (0.00 sec)
摸拟恢复操作:
step 1:找到误操作的log position
dbadmin@test 11:20:57>show master logs;
dbadmin@(none) 11:21:37>show binlog events in 'mysql-bin.000004';
查看可以看到是444
step 2:
恢复到备份
dbadmin@test 11:16:25>source test.sql
dbadmin@test 11:17:26>select * from t;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
step 3:
因为我们在备份的时候使用了master-data的参数,所以可以直接看到备份时候的最后位置,然后应用中间的log。
查看可以看到是187
我们使用mysqlbinlog得到这一段时间的操作,其实我们也可以用这个工具得到操作后使用sed进行undo的操作。
mysqlbinlog --start-position=187 --stop-position=444 mysql-bin.000004 > increment.sql
dbadmin@test 11:44:37>source /u01/my3307/log/increment.sql
dbadmin@test 11:44:50>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
+------+
至此数据恢复。
是ORACLE公司提供的针对企业的备份软件,全名叫做MySQL Enterprise Backup,是一个收费的软件。 下载地址:https://www.mysql.com/products/enterprise/backup.html 可以试用下载。我们简单的来看一下这个工具的使用。
查看所有的帮助:
我这里只是截取了一小部分,这个帮助很长,参数很多,功能很全,是oracle官方主推的备份方式。
全量备份
mysqlbackup --user=root --password=ucjmh --databases='t1' --encrypt-password=1 --with-timestamp --backup-dir=/u01/backup/ backup
解释一下参数:
--databases 要备份的数据库
--with-timestamp 产生一个当前时间的备份目录。mysqlbackup这个工具要求一个空目录才能做备份。所以这个会常用
--backup-dir 备份的目录
--compress:压缩备份 这个提供了多种压缩方法和压缩级别。1--9,压缩比依次递增
backup 是备份的方式,
一共有如下几种方式,我会在一个恢复案例里把常用的几个都用到
Backup operations: backup, backup-and-apply-log, backup-to-image
Update operations: apply-log, apply-incremental-backup
Restore operations: copy-back, copy-back-and-apply-log
Validation operation: validate
Single-file backup operations: image-to-backup-dir, backup-dir-to-image, list-image, extract
其实,在大多数情况下,单个文件备份,使用backup-to-image命令创建,性能优于backup。buckup这个命令只执行一个完整的备份过程的初始阶段。需要通过再次运行mysqlbackup运用apply-log 命令,使备份一致。
mysqlbackup --user=root --password=ucjmh --databases='t1' --encrypt-password=1 --with-timestamp --backup-dir=/u01/backup/2017-04-28_12-49-35/ apply-log
当然你可以直接用backup-and-apply-log 不过这个时候的备份将不能用于增量了。
增量备份:
mysqlbackup --user=root --password=ucjmh --databases='t1' --encrypt-password=1 --with-timestamp --backup-dir=/u01/backup/ --incremental --incremental-base=dir:/u01/backup/2017-04-28_12-49-35 --incremental-backup-dir=/u01/backup/incremental backup
这个是基于上次的备份做的备份,当然也可以基于某一个log position之后做。
--incremental:代表增量备份;
--incremental-base:上次全备的目录;
--incremental-backup-dir:增量备份的保存的目录
再多说一点关于image的备份:
使用如下命令可以进行备份
mysqlbackup --user=root --password=ucjmh --databases='t1' --encrypt-password=1 --with-timestamp --backup-dir=/u01/backup/ --backup-image=all.mbi backup-to-image
备份之后可以很清楚的发现这个比backup要节省很多空间,把所有的文件都以二进制的方式放在了all.mbi这个文件里,可以使用list-image来查看具体内容。
mysqlbackup --backup-image=/u01/backup/2017-04-28_14-50-17/all.mbi list-image
同样的也可以使用
mysqlbackup --backup-image=/u01/backup/2017-04-28_14-50-17/all.mbi extract
来解压出来具体的内容。
因为这是一个oracle出的工具,有很深的rman的影子在,0级,1级备份,加密,异构机器还原等特性。
更多的参数可以参看online help:
https://dev.mysql.com/doc/mysql-enterprise-backup/4.1/en/backup-commands-single-file.html
恢复操作:
查看当前数据
dbadmin@test 11:51:32>select * from t;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.01 sec)
全量备份
mysqlbackup --user=root --password=root@1234 --databases='test' --with-timestamp --backup-dir=/data/backup/ backup
模拟增量操作:
dbadmin@test 11:54:04>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)
增量备份:
mysqlbackup --user=root --password=root@1234 --databases='test' --with-timestamp --backup-dir=/data/backup/ --incremental --incremental-base=dir:/data/backup/2017-04-29_11-53-20 --incremental-backup-dir=/data/backup/incremental backup
模拟无备份操作:
dbadmin@test 11:57:10>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
模拟误操作:
dbadmin@test 11:57:17>truncate table t;
Query OK, 0 rows affected (0.01 sec)
摸拟恢复操作:
step 1:找到误操作的log position
dbadmin@test 11:58:06>show master logs;
dbadmin@test 11:58:18>show binlog events in 'mysql-bin.000001';
1333
step 2:恢复全量
检测并应用日志:
mysqlbackup --backup-dir=/data/backup/2017-04-29_11-53-20 apply-log
step 3:应用增量
mysqlbackup --backup-dir=/data/backup/2017-04-29_11-53-20 --incremental-backup-dir=/data/backup/incremental/2017-04-29_11-55-54 apply-incremental-backup
step 4:物理文件复制还原
mysqlbackup --backup-dir=/data/backup/2017-04-29_11-53-20 copy-back
数据恢复到备份的时候:
dbadmin@test 12:09:49>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)
恢复完成之后,data目录下会生成backup_variables.txt的文件(其实在备份的时候就已经有这些文件的),找到备份的时候的log position,然后从binlog恢复无备份的数据
binlog_position=mysql-bin.000001:1076
mysqlbinlog mysql-bin.000001 --start-position=1076 --stop-position=1333 -vv >increment.sql
dbadmin@test 12:14:07>source /u01/my3307/log/increment.sql
dbadmin@test 12:14:16>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
至此数据恢复。
大致梳理一下操作步骤,来了解一下恢复的原理:
首先检测并应用全备事务日志文件(这里是因为我备份的时候用的是backup而不是backup-and-apply-log),然后基于全备去应用增量的log。这个时候如果有多次增量备份也可以(基于LSN点向后应用)。 所有的都应用完成之后就是一个可以直接cp的数据库了。
个人感觉这个工具比xtrabackup好用,但是xtrabackup是开源的,所以市场占有量才会大,才会更有名,更多人用吧。
mysqlhotcopy使用lock tables、flush tables和cp或scp来快速备份数据库.它是备份数据库或单个表最快的途径,完全属于物理备份,但只能用于备份MyISAM存储引擎和ARCHIVE引擎,并且是一个服务器命令,只能运行在数据库目录所在的机器上.与mysqldump备份不同,mysqldump属于逻辑备份,备份时是执行的sql语句.使用mysqlhotcopy命令前需要要安装相应的软件依赖包.
因为这个功能很弱,我们只简单的介绍一个怎么用:
备份一个库
mysqlhotcopy db_name [/path/to/new_directory]
备份一张表
mysqlhotcopy db_name./table_name/ /path/to/new_directory
更详细的使用可以使用perldoc mysqlhotcopy查看
Percona XtraBackup是一款基于MySQL的热备份的开源实用程序,它可以备份5.1到5.7版本上InnoDB,XtraDB,MyISAM存储引擎的表,
Xtrabackup有两个主要的工具:xtrabackup、innobackupex
(1)xtrabackup只能备份InnoDB和XtraDB两种数据表,而不能备份MyISAM数据表
(2)innobackupex则封装了xtrabackup,是一个脚本封装,所以能同时备份处理innodb和myisam,但在处理myisam时需要加一个读锁
首先我们先来简单的了解一下xtrabackup是怎么工作的。xtrabackup基于innodb的crash-recovery(实例恢复)功能,先copy innodb的物理文件(这个时候数据的一致性是无法满足的),然后进行基于redo log进行恢复,达到数据的一致性。详细的信息可以参数https://www.percona.com/doc/percona-xtrabackup/LATEST/how_xtrabackup_works.html 我就不翻译了。
我们还是简单的来看一下日常工作中具体的使用:
全备:
xtrabackup --backup --target-dir=/data/backup/base
可以先看到
在备份过程中,可以看到很多输出显示数据文件被复制,以及日志文件线程反复扫描日志文件和复制。
同样的它也输出了当前的binlog filename和position,如果有gtid(同样也会输出) 可以用于搭建主从。最后一行一定会是你的lsn被copy的信息。
这是因为每次启动备份,都会记录170429 12:54:10 >> log scanned up to (1676085)),然后开始拷贝文件,一般来讲数据库越大拷贝文件是要花费越长的时间,所以说这期间一般情况都会有新的操作,所以说所有文件也可能记录的并不是一个时间点的数据,
为了解决数据这个问题,XtraBackup 就会启动一个后台进程来每秒1次的观测mysql的事务日志,直到备份结束。而且把事务日志中的改变记录下来。我们知道事物日志是会重用的(redo log),所以这个进程会把redolog写到自己的日志文件xtrabackup_log,这个后台监控进程会记录所有的事务日志的改变,用于保证数据一致性所。
增量备份:
当我们做过全量备份以后会在目录下产生xtrabackup_checkpoints的文件 这里面记录了lsn和备份方式,我们可以基于这次的全量做增量的备份。
$cat xtrabackup_checkpoints
backup_type = full-backuped
from_lsn = 0
to_lsn = 1676085
last_lsn = 1676085
compact = 0
recover_binlog_info = 0
xtrabackup --backup --target-dir=/data/backup/inc1 --incremental-basedir=/data/backup/base
这个时候xtrabackup也是去打开了xtrabackup_checkpoints文件进行上一次备份的信息查看。这个时候去查看增量备份的xtrabackup_checkpoints也记录了这些信息
$cat xtrabackup_checkpoints
backup_type = incremental
from_lsn = 1676085
to_lsn = 1676085
last_lsn = 1676085
compact = 0
recover_binlog_info = 0
这也意味着你可以在增量的备份上继续增量的备份。
同样的xtrabackup也支持压缩(--compress)、加密(--encrypt)、并行(--parallel)等操作,但是和mysqlbackup不同的是这个没有同时的备份binlog,而mysqlbackup是备份了binlog的。
我们来模拟一个恢复的过程深入的了解一下原理
查看当前数据:
dbadmin@test 03:04:33>select * from t;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
全量备份
$xtrabackup --backup --target-dir=/data/backup/base
模拟增量数据
dbadmin@test 03:07:16>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)
进行增量备份:
$xtrabackup --backup --target-dir=/data/backup/inc1 --incremental-basedir=/data/backup/base
模拟无备份操作:
dbadmin@test 03:09:42>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
模拟误操作:
dbadmin@test 03:09:45>truncate table t;
Query OK, 0 rows affected (0.00 sec)
摸拟恢复操作:
step 1:找到误操作的log position
dbadmin@test 03:10:19>show master logs;
dbadmin@test 03:10:47>show binlog events in 'mysql-bin.000001';
1333
我们需要分别对全量、增量备份各做一次prepare操作。
xtrabackup --prepare --apply-log-only --target-dir=/data/backup/base
增量
xtrabackup --prepare --apply-log-only --target-dir=/data/backup/base \
--incremental-dir=/data/backup/inc1
如果我们使用它自带的还原命令的时候就要先把data目录给清空。不然就会报如下的错误
$innobackupex --copy-back /data/backup/base/
170429 15:37:19 innobackupex: Starting the copy-back operation
IMPORTANT: Please check that the copy-back run completes successfully.
At the end of a successful copy-back run innobackupex
prints "completed OK!".
innobackupex version 2.4.6 based on MySQL server 5.7.13 Linux (x86_64) (revision id: 8ec05b7)
Original data directory /u01/my3307/data is not empty!
当然我们大多数据时候是不会在原来的实例上做操作的,都会把相应的备份在奇他的实例上进行恢复,然后再导出导入到误操作的实例。这里我们直接清掉目录,然后再次运行,查看恢复后的数据:
dbadmin@test 03:41:56>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
+------+
2 rows in set (0.00 sec)
同样的被恢复的目录里会多出来两个文件,一个是xtrabackup_binlog_pos_innodb,一个是xtrabackup_info。在这两个文件中都可以看到你最后的log,pos。在info里还可以看到lsn。我们基于这个pos再进行binlog的重演,恢复在binlog没有被备份的数据。
1076
$mysqlbinlog mysql-bin.000001 --start-position=1076 --stop-position=1333 -vv >increment.sql
dbadmin@test 03:51:25>source /u01/my3307/log/increment.sql
dbadmin@test 03:51:34>select * from t;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
至此数据恢复完成
https://www.percona.com/doc/percona-xtrabackup/LATEST/backup_scenarios/full_backup.html
MySQL有一种非常简单的备份方法,就是将MySQL中的数据库文件直接复制出来。这是最简单,速度最快的方法。
不过在此之前,要先将服务器停止,这样才可以保证在复制期间数据库的数据不会发生变化。如果在复制数据库的过程中还有数据写入,就会造成数据不一致。这种情况在开发环境可以,但是在生产环境中很难允许备份服务器。
注意:这种方法不适用于InnoDB存储引擎的表,而对于MyISAM存储引擎的表很方便。同时,还原时MySQL的版本最好相同。
只所以提这一点是因为当有停机窗口时,搭建主从的时候,这个往往是最快的。
3.索引
索引是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能非常关键。不过索引却经常被忽略,有时候甚至被误解,所以在实际案例中经常会遇到由糟糕索引导致的问题。索引优化应该是对查询性能优化最有效的手段。
当人们谈论索引的时候如果没有特别的指明类型,一般说的是B-Tree索引。它使用B-Tree数据结构来存储数据。B-Tree通常意味着所有的键都是按顺序存储的并且每一个页到根的距离相同。由于是按照顺序存储数据,所以MySQL可以用来做ORDER BY和GROUP BY操作。
建立原则:
1.最左前缀匹配原则:非常重要的原则,MySQL会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立key(a,b,c,d)顺序的索引,d是用不到索引的,如果建立key(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
2.索引列不能参与计算:如a + 5 = ${num}、from_unixtime(create_time) = ${date},就不能使用到索引。因为B-Tree中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成a = ${num} - 5。
3.尽量的扩展索引:比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
有效查询:
1.全值匹配:指的是和索引中的所有列进行匹配,如key(a,b):a = 1 and b = 2;
2.匹配最左前缀:就是按照索引的列从左向右开始查找,不能跳过索引中的列,如key(a,b,c,d):a =1 and b=2为最左前缀,a =1 and c=3则不是;
3.匹配列前缀:可以匹配某一列的值的开头部分,如key(a):a like‘${name}%;
4.匹配范围值:B-Tree对索引列是顺序存储的,所以很适合查找范围数据。除了按值查找之外,索引还可以用于ORDER BY操作;
5.精确匹配某一列并范围匹配另一列:参照最左匹配原则;
哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。在MySQL中只有Memory引擎显示支持哈希索引。InnoDB引擎有一个特殊的功能叫做“自适应哈希索引”。当InnoDB注意到某些索引值被使用得非常频繁时,它会在内存中基于B-Tree索引之上在创建一个哈希索引,这样让B-Tree索引也具有哈希索引的一些有点。
因为索引自身只需存储对应的哈希值,所以索引结构十分紧凑,这也让哈希索引查找速度非常快。
特性:
1.哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中的行的速度很快,所以大部分情况下这一点对性能的影响并不明显。
2.哈希索引数据并不是按照索引值顺序存储,所以无法用于排序。
3.哈希索引也不支持部分索引列匹配查找,因为哈希索引始终是使用索引列的全部内容来计算哈希值。
4.哈希索引只支持等值比较,包括=、IN()、<=>(注意<>和<=>是不同的操作),不支持范围查询。
5.访问哈希索引的数据非常快,除非有很多哈希冲突。当出现哈希冲突的时候,存储引擎必须遍历链表中的所有的行指针,逐行进行比较,直到找到所有符合条件的行。如果哈希冲突很多的话,一些索引维护操作的代价也会很高。
创建自定义哈希索引:
如果存储引擎不支持哈希索引,则可以模拟像InnoDB一样创建哈希索引。例如只需要很小的索引就可以为超长的键创建索引。
创建方法:在B-Tree的基础上创建一个伪哈希索引。这和真正的哈希索引不是一回事,因为还是使用B-Tree索引进行查找,但是它使用哈希值而不是键本身进行索引查找。你需要做的就是在查询的WHERE子句中手动指定使用哈希函数。
例如:需要存储大量的URL,并需要根据URL进行搜索查找。如果使用B-Tree来存储URL,存储的内容就会很大。若删除原来的URL列上的索引,而新增一个被索引的url_crc列,使用CRC32做哈希,就可以使用下面的方式查询:
SELECT …… WHERE url=”http://www.mysql.com” AND url_crc = CRC32(“http://www.mysql.com”);
这样做的性能会非常高,因为MySQL优化器会使用这个选择性很高而体积很小的索引来完成查找。即使有多个记录有重复的索引值,查找仍然很快。
聚簇索引也叫簇类索引,聚簇索引并不是一种单独的索引类型,是一种对磁盘上实际数据重新组织以按指定的一个或多个列的值排序。因为无法同时把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
具体的细节依赖于其实现方式,InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。InnoDB通过主键聚集数据,如果没有定义主键,InnoDB会选择一个唯一的非空索引代替。如果没有这样的索引,InnoDB会隐式定义一个主键作为聚簇索引。
特点:
1.可以把相关数据保存在一起。这样只需要从磁盘读取少数的数据页就能获取全部需要的数据。
2.数据访问更快。由于聚簇索引的索引页面指针指向数据页面,所以使用聚簇索引查找数据几乎总是比使用非聚簇索引快。
3.使用覆盖索引扫描的查询可以直接使用页节点中的主键值。
4.聚簇索引最大限度地提高率I/O密集型应用的性能,但如果数据全部都放在内存中,则访问的顺序就没那么重要了。
5.插入速度严重依赖于插入顺序。按照主键顺序插入是速度最快的方式。
6.更新聚簇索引的代价很高,会将每个被更新的行移动到新的位置。
如果一个索引包含所有需要查询的字段的值,我们就称之为“覆盖索引”。使用索引来直接获取列的数据,这样就不在需要读取数据行。覆盖索引是非常有用的工具,能够极大的提高性能。MySQL只能使用B-Tree索引做覆盖索引。
1.索引条目通常远小于数据行大小,所以如果只需要读取索引,那MySQL就会极大的减少数据访问量。
2.因为索引是按照列值顺序存储的,所以对于I/O密集型的范围查询会比随机从磁盘读取每一行数据的I/O要少得多。
3.由于InnoDB的聚簇索引,覆盖索引对InnoDB表特别有用。
空间索引可以用作地理数据存储。空间索引会从所有纬度来索引数据。查询时可以有效地使用任意维度来组合查询。MySQL的GIS支持并不完善,所以大部分人都不会使用这个特性。
全文索引是一种特殊类型的索引,他查找的是文本中的关键词,而不是直接比较索引中的值。全文搜索和其他几类索引的匹配方式不一样。它有许多需要注意的细节,如停用词、词干和复数、布尔搜索等。全文索引更类似于搜索引擎做的事情,而不是简单的WHERE条件匹配。在相同的列同时创建全文索引和B-Tree索引不会有冲突,全文索引适用于MATCH AGAINST操作。
独立的列:
“独立的列”是指索引列不能是表达式的一部分,也不能是函数。如果查询中的列不是独立的,则MySQL就不会使用索引。
例如:SELECT…… WHERE id + 1 = 5;
SELECT …… WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(data_col) <= 10;
都是错误的写法。
前缀索引和索引选择性:
有时候需要索引很长的字符列,这会让索引变得大且慢。一个策略是前面提到过的模拟哈希索引。但有时候这样做还不够,通常可以索引开始的部分字符串。但这样也会降低索引的选择性。一般情况下某列前缀的选择性也是足够高的,足以满足查询性能。对于BLOB、TEXT或者很长的VARCHAR类型的列,必须使用前缀索引。
多列索引:
很多人对多列索引的理解不够,一个常见的错误就是为每个列创建独立的索引或者按照错误的顺序创建多列索引。在多个列上建立独立的单列索引大部分情况下并不能提高MySQL的查询性能。当出现服务器对多个索引做相交操作时,通常意味着需要一个包含所有相关列的多列索引,而不是多个独立的单列索引。
使用索引扫描来做排序:
MySQL有两种方式可以生成有序的结果:通过排序操作,或者按索引顺序扫描。MySQL可以使用同一个索引既满足排序,又用于查找行。因此,如果可能,设计索引时应该尽可能地同时满足这两种任务。
只有当索引的列顺序和ORDER BY子句的顺序完全一致,既需要满足最左前缀要求,并且所有列的排序方向(顺序或者倒序)都一样时,MySQL才能使用索引来对结果做排序。如果查询需要关联多张表,则只有当ORDER BY子句引用的字段全部为第一张表时,才能使用索引做排序。
多余的索引:
MySQL允许在相同的列上创建多个索引,MySQL需要单独维护重复的索引,并且优化器在优化查询的时候也需要逐个地进行考虑,这会影响性能。应该避免这样创建重复的索引,发现以后也应该立即移除。
可能还会有一些服务器永远不用的索引,这样的索引也应该考虑删除。