基础入门: 与MySQL的零距离接触-慕课网html
MySQL开发技巧: MySQL开发技巧(一) MySQL开发技巧(二) MySQL开发技巧(三)java
MySQL5.7新特性及相关优化技巧: MySQL5.7版本新特性 性能优化之MySQL优化mysql
MySQL 是一种关系型数据库,在Java企业级开发中很是经常使用,由于 MySQL 是开源免费的,而且方便扩展。阿里巴巴数据库系统也大量用到了 MySQL,所以它的稳定性是有保障的。MySQL是开放源代码的,所以任何人均可以在 GPL(General Public License) 的许可下下载并根据个性化的须要对其进行修改。MySQL的默认端口号是3306。github
查看MySQL提供的全部存储引擎面试
mysql> show engines;
从上图咱们能够查看出 MySQL 当前默认的存储引擎是InnoDB,而且在5.7版本全部的存储引擎中只有 InnoDB 是事务性存储引擎,也就是说只有 InnoDB 支持事务。redis
查看MySQL当前默认的存储引擎算法
咱们也能够经过下面的命令查看默认的存储引擎。sql
mysql> show variables like '%storage_engine%';
查看表的存储引擎数据库
show table status like "table_name" ;
MyISAM是MySQL的默认数据库引擎(5.5版以前)。虽然性能极佳,并且提供了大量的特性,包括全文索引、压缩、空间函数等,但MyISAM不支持事务和行级锁,并且最大的缺陷就是崩溃后没法安全恢复。不过,5.5版本以后,MySQL引入了InnoDB(事务性数据库引擎),MySQL 5.5版本后默认的存储引擎为InnoDB。
大多数时候咱们使用的都是 InnoDB 存储引擎,可是在某些状况下使用 MyISAM 也是合适的好比读密集的状况下。(若是你不介意 MyISAM 崩溃恢复问题的话)。
二者的对比:
READ COMMITTED
和 REPEATABLE READ
两个隔离级别下工做;MVCC可使用 乐观(optimistic)锁 和 悲观(pessimistic)锁来实现;各数据库中MVCC实现并不统一。推荐阅读:MySQL-InnoDB-MVCC多版本并发控制《MySQL高性能》上面有一句话这样写到:
不要轻易相信“MyISAM比InnoDB快”之类的经验之谈,这个结论每每不是绝对的。在不少咱们已知场景中,InnoDB的速度均可以让MyISAM可望不可即,尤为是用到了聚簇索引,或者须要访问的数据均可以放入内存的应用。
通常状况下咱们选择 InnoDB 都是没有问题的,可是某些状况下你并不在意可扩展能力和并发能力,也不须要事务支持,也不在意崩溃后的安全恢复问题的话,选择MyISAM也是一个不错的选择。可是通常状况下,咱们都是须要考虑到这些问题的。
字符集指的是一种从二进制编码到某类字符符号的映射。校对规则则是指某种字符集下的排序规则。MySQL中每一种字符集都会对应一系列的校对规则。
MySQL采用的是相似继承的方式指定字符集的默认值,每一个数据库以及每张数据表都有本身的默认值,他们逐层继承。好比:某个库中全部表的默认字符集将是该数据库所指定的字符集(这些表在没有指定字符集的状况下,才会采用默认字符集) PS:整理自《Java工程师修炼之道》
详细内容能够参考: MySQL字符集及校对规则的理解
MySQL索引使用的数据结构主要有BTree索引 和 哈希索引 。对于哈希索引来讲,底层的数据结构就是哈希表,所以在绝大多数需求为单条记录查询的时候,能够选择哈希索引,查询性能最快;其他大部分场景,建议选择BTree索引。
MySQL的BTree索引使用的是B树中的B+Tree,但对于主要的两种存储引擎的实现方式是不一样的。
更多关于索引的内容能够查看文档首页MySQL目录下关于索引的详细总结。
执行查询语句的时候,会先查询缓存。不过,MySQL 8.0 版本后移除,由于这个功能不太实用
my.cnf加入如下配置,重启MySQL开启查询缓存
query_cache_type=1 query_cache_size=600000
MySQL执行如下命令也能够开启查询缓存
set global query_cache_type=1; set global query_cache_size=600000;
如上,开启查询缓存后在一样的查询条件以及数据状况下,会直接在缓存中返回结果。这里的查询条件包括查询自己、当前要查询的数据库、客户端协议版本号等一些可能影响结果的信息。所以任何两个查询在任何字符上的不一样都会致使缓存不命中。此外,若是查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL库中的系统表,其查询结果也不会被缓存。
缓存创建以后,MySQL的查询缓存系统会跟踪查询中涉及的每张表,若是这些表(数据或结构)发生变化,那么和这张表相关的全部缓存数据都将失效。
缓存虽然可以提高数据库的查询性能,可是缓存同时也带来了额外的开销,每次查询后都要作一次缓存操做,失效后还要销毁。 所以,开启缓存查询要谨慎,尤为对于写密集的应用来讲更是如此。若是开启,要注意合理控制缓存空间大小,通常来讲其大小设置为几十MB比较合适。此外,还能够经过sql_cache和sql_no_cache来控制某个查询语句是否须要缓存:
select sql_no_cache count(*) from usr;
事务是逻辑上的一组操做,要么都执行,要么都不执行。
事务最经典也常常被拿出来讲例子就是转帐了。假如小明要给小红转帐1000元,这个转帐会涉及到两个关键操做就是:将小明的余额减小1000元,将小红的余额增长1000元。万一在这两个操做之间忽然出现错误好比银行系统崩溃,致使小明余额减小而小红的余额没有增长,这样就不对了。事务就是保证这两个关键操做要么都成功,要么都要失败。
在典型的应用程序中,多个事务并发运行,常常会操做相同的数据来完成各自的任务(多个用户对同一数据进行操做)。并发虽然是必须的,但可能会致使如下的问题。
不可重复读和幻读区别:
不可重复读的重点是修改好比屡次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除好比屡次读取一条记录发现记录增多或减小了。
SQL 标准定义了四个隔离级别:
隔离级别 | 脏读 | 不可重复读 | 幻影读 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。咱们能够经过SELECT @@tx_isolation;
命令来查看
mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+
这里须要注意的是:与 SQL 标准不一样的地方在于 InnoDB 存储引擎在 REPEATABLE-READ(可重读) 事务隔离级别下使用的是Next-Key Lock 锁算法,所以能够避免幻读的产生,这与其余数据库系统(如 SQL Server) 是不一样的。因此说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读) 已经能够彻底保证事务的隔离性要求,即达到了 SQL标准的 SERIALIZABLE(可串行化) 隔离级别。由于隔离级别越低,事务请求的锁越少,因此大部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容) ,可是你要知道的是InnoDB 存储引擎默认使用 REPEAaTABLE-READ(可重读) 并不会有任何性能损失。
InnoDB 存储引擎在 分布式事务 的状况下通常会用到 SERIALIZABLE(可串行化) 隔离级别。
MyISAM和InnoDB存储引擎使用的锁:
表级锁和行级锁对比:
详细内容能够参考: MySQL锁机制简单了解一下:http://www.javashuo.com/article/p-omwesioc-ba.html
InnoDB存储引擎的锁的算法有三种:
相关知识点:
当MySQL单表记录数过大时,数据库的CRUD性能会明显降低,一些常见的优化措施以下:
务必禁止不带任何限制数据范围条件的查询语句。好比:咱们当用户在查询订单历史的时候,咱们能够控制在一个月的范围内;
经典的数据库拆分方案,主库负责写,从库负责读;
根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登陆信息又有用户的基本信息,能够将用户表拆分红两个单独的表,甚至放到单独的库作分库。
简单来讲垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。 以下图所示,这样来讲你们应该就更容易理解了。
保持数据表结构不变,经过某种策略存储数据分片。这样每一片数据分散到不一样的表或者库中,达到了分布式的目的。 水平拆分能够支撑很是大的数据量。
水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时能够把一张的表的数据拆成多张表来存放。举个例子:咱们能够将用户信息表拆分红多个用户信息表,这样就能够避免单一表数据量过大对性能形成影响。
水平拆分能够支持很是大的数据量。须要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但因为表的数据仍是在同一台机器上,其实对于提高MySQL并发能力没有什么意义,因此 水平拆分最好分库 。
水平拆分可以 支持很是大的数据量存储,应用端改造也少,但 分片事务难以解决 ,跨节点Join性能较差,逻辑复杂。《Java工程师修炼之道》的做者推荐 尽可能不要对数据进行分片,由于拆分会带来逻辑、部署、运维的各类复杂度 ,通常的数据表在优化得当的状况下支撑千万如下的数据量是没有太大问题的。若是实在要分片,尽可能选择客户端分片架构,这样能够减小一次和中间件的网络I/O。
下面补充一下数据库分片的两种常见方案:
详细内容能够参考: MySQL大表优化方案: http://www.javashuo.com/article/p-cclvigrf-k.html
池话设计应该不是一个新名词。咱们常见的如java线程池、jdbc链接池、redis链接池等就是这类设计的表明实现。这种设计会初始预设资源,解决的问题就是抵消每次获取资源的消耗,如建立线程的开销,获取远程链接的开销等。就比如你去食堂打饭,打饭的大妈会先把饭盛好几份放那里,你来了就直接拿着饭盒加菜便可,不用再临时又盛饭又打菜,效率就高了。除了初始化资源,池化设计还包括以下这些特征:池子的初始值、池子的活跃值、池子的最大值等,这些特征能够直接映射到java线程池和数据库链接池的成员属性中。——这篇文章对池化设计思想介绍的还不错,直接复制过来,避免重复造轮子了。
数据库链接本质就是一个 socket 的链接。数据库服务端还要维护一些缓存和用户权限信息之类的 因此占用了一些内存。咱们能够把数据库链接池是看作是维护的数据库链接的缓存,以便未来须要对数据库的请求时能够重用这些链接。为每一个用户打开和维护数据库链接,尤为是对动态数据库驱动的网站应用程序的请求,既昂贵又浪费资源。**在链接池中,建立链接后,将其放置在池中,并再次使用它,所以没必要创建新的链接。若是使用了全部链接,则会创建一个新链接并将其添加到池中。**链接池还减小了用户必须等待创建与数据库的链接的时间。
由于要是分红多个表以后,每一个表都是从 1 开始累加,这样是不对的,咱们须要一个全局惟一的 id 来支持。
生成全局 id 有下面这几种方式: