文章较长
MySQL DBMS - MySQL Database Management System。数据库管理系统。
ISAM 是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到数 据库被查询的次数要远大于更新的次数。因此,ISAM 执行读取操作的速度很快,而且不占 用大量的内存和存储资源。ISAM 的两个主要不足之处在于,它不支持事务处理,也不能够容错。如果你的硬盘崩溃了,那么数据文件就无法恢复了。如果你正在把 ISAM 用在关键任 务应用程序里,那就必须经常备份你所有的实时数据,通过其复制特性,MYSQL 能够支持 这样的备份应用程序。
注意: 使用ISAM注意点:必须经常备份所有实时数据。
MyISAM 是 MySQL 的 ISAM 扩展格式(MySQL5.5 之前版本的缺省数据库引擎)数据库 引擎。除了提供 ISAM 里所没有的索引和字段管理的大量功能,MyISAM 还使用一种表格锁 定的机制,来优化多个并发的读写操作,其代价是你需要经常运行 PTIMIZETABLE 命令, 来恢复被更新机制所浪费的空间。MyISAM 还有一些有用的扩展,例如用来修复数据库文件 的 MyISAMCHK 工具和用来恢复浪费空间的 MyISAMPACK 工具。MYISAM 强调了快速读取操作,这可能就是为什么 MySQL 受到了WEB开发如此青睐的主要原因:在 WEB 开发中你所进行的大量数据操作都是读取操作。所以,大多数虚拟主机提供商和 INTERNET 平台提供商 只允许使用 MYISAM 格式。MyISAM格式的一个重要缺陷就是不能在表损坏后恢复数据 。(也不支持事务)
MyISAM 引擎使用注意:必须经常使用 OptimizeTable 命令清理空间;必须经常备份所 有实时数据。工具有用来修复数据库文件的 MyISAMCHK 工具和用来恢复浪费空间的MyISAMPACK 工具。不支持事务。数据越多,写操作效率越低。因为要维护数据和索 引信息 。(因为要维护数据和索引信息,索引列越多,相对效率越低)
如果使用该数据库引擎,会生成三个文件:
.frm:表结构信息
.MYD:数据文件
.MYI:表的索引信息
InnoDB 数据库引擎都是造就 MySQL 灵活性的技术的直接产品,这项技术就是 MYSQL++ API。在使用 MYSQL 的时候,你所面对的每一个挑战几乎都源于 ISAM 和 MyISAM 数据库引擎不支持事务处理(transactionprocess)也不支持外键。尽管要比 ISAM 和 MyISAM 引擎慢很多,但是 InnoDB 包括了对事务处理和外键的支持,这两点都是前两个引擎所没有的。 是现在的 MySQL(5.5 以上版本)常用版本默认引擎 MySQL 官方对 InnoDB 是这样解释的:InnoDB 给 MySQL 提供了具有提交、回滚和崩溃恢复能力的事务安全(ACID 兼容)存储引擎。InnoDB 锁定在行级并且也在 SELECT 语句提 供一个 Oracle 风格一致的非锁定读,这些特色增加了多用户部署的性能。没有在 InnoDB 中 扩大锁定的需要,因为在 InnoDB 中行级锁定适合非常小的空间。 InnoDB 也支持 FOREIGNKEY 强制。在 SQL 查询中,你可以自由地将 InnoDB 类型的表与其它 MySQL 的表的类型混合起来,甚至在同一个查询中也可以混合。
InnoDB 是为处理巨大数据量时的最大性能设计,它的 CPU 效率可能是任何其它基于 磁盘的关系数据库引擎所不能匹敌的。 InnoDB 存储引擎被完全与 MySQL 服务器整合, InnoDB 存储引擎为在主内存中缓存数据 和索引而维持它自己的缓冲池。InnoDB 存储它的表&索引在一个表空间中,表空间可以包含数个文件(或原始磁盘分区)。这与 MyISAM 表不同,比如在 MyISAM 表中每个表被存在 分离的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制为 2GB 的操作系统上。
在 MySQL5.7 版本中,InnoDB 存储引擎管理的数据文件为两个:分别是 frm,idb 文件。(默认数据库引擎)
InnoDB 特 点 :
1. 支 持 事 务
2. 数 据 多 版 本 读 取 ( InnoDB+MyISAM+ISAM)
3. 锁 定 机 制 的 改 进
4 . 实现外键
Memory 存储引擎,通过名字就很容易让人知道,他是一个将数据存储在内存中的存储引擎。Memory 存储引擎不会将任何数据存放到磁盘上,仅仅存放了一个表结构相关信息 的.frm 文件在磁盘上面。所以一旦 MySQL Crash 或者主机 Crash 之后,Memory 的表就只剩下一个结构了。Memory 表支持索引(不支持事务),并且同时支持 Hash 和 B-Tree 两种格式的索引。由于是存放在内存中,所以 Memory 都是按照定长的空间来存储数据的,而且不支持 BLOB 和 TEXT 类型的字段。Memory 存储引擎实现页级锁定。
存储引擎NDB存储引擎也叫NDBCluster存储引擎,主要用于MySQLCluster分布式集群环境,Cluster是MySQL从5.0版本才开始提供的新功能。
MERGE存储引擎,在MySQL用户手册中也提到了,也被大家认识为MRG_MyISAM
引擎。Why?因为MERGE存储引擎可以简单的理解为其功能就是实现了对结构相同的MyISAM表,通过一些特殊的包装对外提供一个单一的访问入口,以达到减小应用的复杂度的目的。要创建MERGE表,不仅仅基表的结构要完全一致,包括字段的顺序,基表的索引也必须完全一致。BDB存储引擎BDB存储引擎全称为BerkeleyDB存储引擎,和Innodb一样,也不是MySQL自己开发实现的一个存储引擎,而是由SleepycatSoftware所提供,当然,也是开源存储引擎,同样支持事务安全。
存储引擎FEDERATED存储引擎所实现的功能,和Oracle的DBLINK基本相似,主要用来提供对远程MySQL服务器上面的数据的访问接口。如果我们使用源码编译来安装MySQL,那么必须手工指定启用FEDERATED存储引擎才行,因为MySQL默认是不起用该存储引擎的。
存储引擎ARCHIVE存储引擎主要用于通过较小的存储空间来存放过期的很少访问的历史数据。
ARCHIVE表不支持索引,通过一个.frm的结构定义文件,一个.ARZ的数据压缩文件还有一
个.ARM的meta信息文件。由于其所存放的数据的特殊性,ARCHIVE表不支持删除,修改操作,仅支持插入和查询操作。锁定机制为行级锁定。
存储引擎BLACKHOLE存储引擎是一个非常有意思的存储引擎,功能恰如其名,就是一个“黑洞”。就像我们unix系统下面的“/dev/null”设备一样,不管我们写入任何信息,都是有去无回。
存储引擎CSV存储引擎实际上操作的就是一个标准的CSV文件,它不支持索引。起主要用途就是大家有些时候可能会需要通过数据库中的数据导出成一份报表文件,而CSV文件是很多软件都支持的一种较为标准的格式,所以我们可以通过先在数据库中建立一张CSV表,然后将生成的报表信息插入到该表,即可得到一份CSV报表文件了。
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
mysql> show variables like '%storage_engine%';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
| storage_engine | InnoDB |
+------------------------+--------+
也可以在 MySQL 配置文件中查看
show create table 表名;
mysql> show create table t_user;
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t_user | CREATE TABLE `t_user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`uname` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 |
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
create table table_name (column_name column_type) engine = engine_name
mysql> create table t_temp (id int(11) primary key,name varchar(255)) engine=myisam;
Query OK, 0 rows affected (0.07 sec)
mysql> show create table t_temp;
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
| t_temp | CREATE TABLE `t_temp` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
alter table table_name engine=engine_name
mysql> alter table t_temp engine = innodb;
Query OK, 0 rows affected (0.11 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table t_temp;
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
| t_temp | CREATE TABLE `t_temp` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
在MySQL 配置文件中修改下述内容:
default-storage-engine=INNODB
MySQL 配置文件:
重启MySQL数据库
为什么要创建索引?这是因为,创建索引可以大大提高系统的查询性能。
也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索 引呢?这种想法固然有其合理性,然而也有其片面性。虽然,索引有许多优点, 但是,为 表中的每一个列都增加索引,是非常不明智的。 这是因为,增加索引也有许多不利的一个方面:
索引是建立在数据库表中的某些列的上面。因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引。 一般来说,应该在具备下述特性的 列上创建索引:
同样,对于有些列不应该创建索引。一般来说,不应该创建索引的这些列具有下述特点:
B-Tree 索引,顾名思义,就是所有的索引节点都按照 balance tree 的数据结构来存储。
B-tree 结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。 B-tree 中,每个结点包含:
对于一棵 m 阶 B-tree,每个结点至多可以拥有 m 个子结点。各结点的关键字和可以拥 有的子结点数都有限制,规定 m 阶 B-tree 中,根结点至少有 2 个子结点,除非根结点为叶 子节点,相应的,根结点中关键字的个数为 1~m-1;非根结点至少有[m/2]([],向上取整) 个子结点,相应的,关键字个数为[m/2]-1~m-1。
B-tree 有以下特性:
由于限制了除根结点以外的非叶子结点,至少含有 M/2 个儿子,确保了结点的至少利用率,其最低搜索性能为:
其中,M 为设定的非叶子结点最多子树个数,N 为关键字总数; 所以 B-树的性能总是等价于二分查找(与 M 值无关) ,也就没有 B 树平衡的问题; 由于 M/2 的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占 M/2 的 结点;删除结点时,需将两个不足 M/2 的兄弟结点合并。
Full-text 索引就是我们常说的全文索引,他的存储结构也是 b-tree。主要是为了解决在我们需要用 like 查询的低效问题。只能解决’xxx%’的 like 查询。
如:字段数据为 ABCDE,索引建立为 - A、AB、ABC、ABCD、ABCDE 五个。
在 MySQL 中,对索引的查看和删除操作是所有索引类型通用的。
这是最基本的索引,它没有任何限制 MyIASM 中默认的 BTREE 类型的索引,也是我们大多数情况下用到的索引。
CREATE INDEX index_name ON table_name(column(length))
ALTER TABLE table_name ADD INDEX index_name(column(length))
CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id),INDEX index_name(title(5)))
与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。 如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似
MySQL 从 3.23.23 版开始支持全文索引和全文检索,FULLTEXT索引仅可用于MyISAM表 ;他们可以从 CHAR 、 VARCHAR或 TEXT列 中作为 CREATETABLE 语句的一部分被创建,或 是随后使用 ALTERTABLE 或 CREATEINDEX 被添加。
对于较大的数据集,将你的资料输入一个没有 FULLTEXT 索引的表中,然后创建索引, 其速度比把资料输入现有 FULLTEXT 索引的速度更为快。不过切记对于大容量的数据表,生 成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。
CREATE TABLE article(id int not null,title varchar(255) , timedate);
平时用的 SQL 查询语句一般都有比较多的限制条件,所以为了进一步榨取 MySQL 的效 率,就要考虑建立组合索引。例如上表中针对 title 和 time 建立一个组合索引:ALTER TABLE article ADD INDEX index_title_time(title(50),time(10))。建立这样的组合索引,其实是相当于分 别建立了下面两组组合索引:
–title,time
–title
为什么没有 time 这样的组合索引呢?这是因为 MySQL 组合索引“最左前缀”的结果。简 单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引, 如下面的几个 SQL 所示:
SELECT * FROM article WHERE title='测试' AND time=1234567890;
SELECT * FROM article WHERE title='测试';
SELECT * FROM article WHERE time=1234567890;
CREATE INDEX index_name ON table_name(column_list)
上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺 点。虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行 INSERT、 UPDATE和 DELETE 次数大于查询次数时,放弃索引。因为更新表时,MySQL 不仅要保存数据,还要 保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。索引只是提高效率的一 个因素,如果你的 MySQL 有大数据量的表,就需要花时间研究建立最优秀的索引,或优化 查询语句。
只要列中包含有 NULL 值都将不会被包含在索引中,组合索引中只要有一列含有 NULL 值,那么这一列对于此组合索引就是无效的。所以我们在数据库设计时不要让字段的默认值 为 NULL。create table table_name (c1 varchar(32) default ‘0’ )
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个 CHAR(255)的列, 如果在前 10 个或 20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和 I/O 操作。 CREATE INDEX index_name ON table_name(column(length))
MySQL 查询只使用一个索引,因此如果 where 子句中已经使用了索引的话,那么 order by 中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
一般情况下不鼓励使用like操作, 如果非使用不可,如何使用也是一个问题。 like“%aaa%” 不会使用索引,而 like“aaa%”可以使用索引。
例如:select * from users where YEAR(adddate)<2007
,将在每个行上进行运算,这将导致索引失效而进行全表扫描 ,因此我们可以改成 : select * from users where adddate<’2007-01-01′
最后总结一下,MySQL 只对以下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。而理论上每张表里面最多可创建16个索引,不过除非是数据量真的很多,否则过多的使用索引也不是那么好玩的。 建议:一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 orderby 涉及的列上建立索引。
应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
selec tid from t where num is null
可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询:
select id from t where num = 0
应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进 行全表扫描,如:
select id from t where num = 10 or num = 20
可以这样查询:
select id from t where num = 10 union all select id from t where num = 20
in 和 notin 也要慎用,否则会导致全表扫描,如:
select id from t1 where num in ( selec tid from t2 where id > 10)
此时外层查询会全表扫描,不使用索引。可以修改为:
select id from t1,( select id from t1 where id > 10 ) t2 where t1.id = t2.id
此时索引被使用,可以明显提升查询效率。
下面的查询也将导致全表扫描:
select id from t where name like '%abc%'
模糊查询如果是必要条件时,可以使用
select id from t where name like 'abc%'
来实现模糊查询,此时索引将被使用。如果头匹配是必要逻辑,建议使用全文搜索引擎(Elasticsearch、 Lucene、Solr 等)。
应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进 行全表扫描。如:
select id from t where num/2=100
应改为:
select id from t where num=100*2
应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)='abc'--name
以 abc 开头的 id 应改为:
select id from t where name like 'abc%'
不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统 将可能无法正确使用索引。
在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
不要写一些没有意义的查询,如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
create table #t(...)
很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)
并不是所有索引对查询都有效,SQL 是根据表中数据来进行查询优化的,当索引列有大 量数据重复时,SQL 查询可能不会去利用索引,如一表中有字段 sex,male、female 几乎各一半,那么即使在 sex 上建了索引也对查询效率起不了作用。
尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每 一个字符,而对于数字型而言只需要比较一次就够了。 尽可能的使用 varchar 代替 char ,因为首先可变长度字段存储空间小,可以节省存储 空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
任何地方都不要使用 select * from t
,用具体的字段列表代替" * "
,不要返回用不到的任何字段。
不使用*、尽量不使用 union,union all 等关键字、尽量不使用 or 关键字、尽量使用等值判断。
表连接建议不超过 5 个。如果超过 5 个,则考虑表格的设计。(互联网应用中)
表连接方式使用外联优于内联。 外连接有基础数据存在。如:A left join B
,基础数据是 A。 A inner join B
,没有基础数据的,先使用笛卡尔积完成全连接,在根据连接条件得到内 连接结果集。
大数据量级的表格做分页查询时,如果页码数量过大,则使用子查询配合完成分页逻辑。
Select * from table limit 1000000,10
Select * from table where id in(select pk from table limit 100000,10)
end…