数据库的应用分为两类:
OLTP(在线事物处理):博客,电子商务,网络游戏等。分区要小心
OLAP(在线分析处理):数据仓库,数据集市。分区可提高查询性能
对于一张大表,一般的B+树需要2~3次的磁盘IO。
连接
TCP/IP,命名管道和共享内存,Unix域套接字。
线程
默认情况下InnoDB有13个后台线程:
- 10 个 IO thread(1 insert buffer, 1 log, 4 read, 4 write)(innodb_read_io_threads & innodb_write_io_threads 参数)
- 1 个 master thread
- 1 个锁监控线程
- 1 个错误监控线程。
master thread:主循环(loop),后台循环(background loop),刷新循环(frush loop),暂停循环(suspend loop)。
内存
缓冲池,重做日志缓冲池,额外的内存池。
将数据库文件按页读取到缓冲池,然后按 LRU 算法来保留在缓冲池中的缓存数据。
如果数据库文件需要修改,总是首先修改在缓存池中的页(脏页),然后按照一定的频率将脏页刷新到文件。
缓冲池中的数据页类型:索引页/数据页/undo页/插入缓存/自适应哈希索引/锁信息/数据字典信息 等。
文件
MySQL通用:参数文件,日志文件,套接字文件,pid文件,表结构定义文件(.frm)。
InnoDB文件:重做日志文件,表空间文件。
日志文件
错误日志
慢查询日志:记录运行实践超过long_query_time阀值的SQL语句。使用mysqldumpslow分析。
查询日志
二进制文件:恢复/复制(主从数据库**)**,通过mysqlbinlog工具查看。
binlog_format参数:
- STATEMENT:日志的逻辑SQL语句;
- ROW:记录表的行更新情况。此时可以将InnoDB的事务隔离基本设定微READ COMMITTED,以获得更好的并发性;
- MIXED:默认为STATEMENT,当有(存储引擎微NDB / 使用了不确定函数 / 使用了INSERT DELAY语句 / 使用了用户定义函数 / 使用了临时表)时为ROW。
表 B+树索引组织
默认主键:
- 非空唯一索引;
- 自动创建一个6个字节大小的指针。
表空间(tabespace) —> 段(segment)—> 区(extent)—> 页(page)
MySQL官方手册中定义的65535(字节)长度是指所有VARCHAR列的长度总和。
对于多字节字符编码的CHAR数据类型的存储,InnoDB在内部将其视为是变长的字符。(和VARCHAR基本没区别)
B+树索引只能找到记录所在的页,数据库吧页载入内存,然后通过Page Directory再进行二叉查找。
数据完整性:
- 实体完整性
- 域完整性
- 参照完整性
InnoDB提供了5种约束:
- Primary Key
- Unique Key
- Foreign Key(参照完整性)
- Default
- NOT NULL
MySQL的外键是即时检查的,可以再导入数据时忽视外键的检查:SET foreign_key_checks = 0;
分区
MySQL支持水平分区,分区是局部分区索引,一个分区中既存放了数据又存放了索引。
- RANGE : PARTITION BY RANGE + VALUES LESS THAN 主要用于日期列的分区(YEAR() / TO_DAYS() / TO_SECONDS() / UNIX_TIMESTAMP())
- LIST : PARTITION BY LIST + VALUES IN 分区列的值是离散的,只能是定义的值(1,3,5,7,9)(2,4,6,8,10)
- [LINEAR] HASH : PARTITION BY HASH (expr) 目的是将数据均匀地分布到预先定义的各个分区中,只需指定一个列值或表达式,以及指定分区数量,MySQL将自动完成(MOD)
- [LINEAR] KEY : PARTITION BY KEY 和HASH相似,但使用MySQL提供的函数进行分区
- [RANGE | LIST] COLUMNS : 可以直接使用非整形的数据进行分区,更好的RANGE | LIST
- 子分区(SUBPARTITION) : 在 RANGE 和 LIST 上再进行 HASH 或 KEY 分区
RANGE 的 NULL值会放入最左边的分区;LIST必须显示指出放在哪个分区
HASH 和 KEY 的任何分区函数都会将含有NULL值的记录返回为0
索引
B+树 : **balance ,B+树由B树和**索引顺序访问方法(ISAM, Indexed Sequential Access Method)演化**而来。所有记录都在叶节点。 B**+树索引并不能找到一个给定键值的具体行,只能找到被参照数据行所在的页。然后数据库把页读入内存,再在内存中二分查找。
- 聚集索引:按照每张表的主键构造一颗B+树,并且叶节点存放着整张表的行记录数据。每张表只能有有一个聚集索引
- 辅助(非)聚集索引:叶节点除了包含键值意外,每个叶级别中的索引行中还包含了一个书签,指向相应行数据的聚集索引键。
- 联合索引:键值的数量大于等于2,可以对第二个键值进行排序。
对于索引的添加或者删除操作,MySQL数据库是先创建一张新的临时表,导入数据,删除原表,更名为原表。
某个字段的取值范围很广,几乎没有重复,既高选择性**,直冲表中取出很少一部分行时(20%),使用B+树索引才有意义。**
自适应哈希索引:数据库中使用链接法解决碰撞,使用除法散列函数 h(k)=k mod m。对于字典类型的查找非常快速。
锁
- 共享锁(S):允许事物读一行数据。
- 排他锁(X):允许是ushanchu或者更新一行数据。
MVCC(多版本并发控制):一致性的非锁定读操作:如果读取的行正在自行DELETE/UPDATE操作,此时读取操作不会等待行上锁的释放,而去读取行的一个快照数据(Undo段),快照可以有多个版本。
SELECT的两种加锁操作(必须在事务中):
- SELECT…FOR UPDATE:对读取的行记录加一个X锁。
- SELECT… LOCK IN SHARE MODE:对读取的行记录加一个S锁。
锁问题:
- 丢失更新
- 脏读:在缓冲池中被修改的数据,并且还没有提交。违反隔离性
- 不可重复读:一个事务两次读之间被另一个事物修改了。违反一致性
发生死锁后,InnoDB会马上回滚一个事务。
事务
ACID:隔离性由锁实现。原子小/一致性/持久性通过redo和undo实现。
- redo(重做日志文件):记录了事务的行为,可以通过其进行“重做”。
- undo:存放在共享表空间undo段:撤销事务。
分布式事务:允许多个独立的事务资源参与一个全局的事务中。要么都提交,要么都回滚。
- 资源管理器
- 事务管理器
- 应用程序
不好的事务习惯:
- 在循环中提交:中途发生错误时,如何回滚前面提交的?
- 使用自动提交
- 使用自动回滚
主从数据库
异步实时进行二进制日志重做。
- 主数据库把数据更新记录到二进制日志中。
- 从服务器把主服务器的二进制日志拷贝到自己的中级日志中。
- 从服务器重做中级日志中的实践,把更新应用到自己的数据库上。
从服务器:两个线程:
- I/O线程:负责读取主服务器的二进制日志,将其保存为中级日志。
- SQL线程,复制执行中继日志。
功能:
- 数据分布:在不同的数据中心之间实现数据的拷贝。
- 读取的均衡负载:通过简历多个从服务器,可将读取平均地分布到这些从服务器中。一般通过DNS的Round-Robin和Linux的LVS功能实现负载平衡。
- 数据库备份。
- 高可用性和故障转移