diff --git a/数据库/MySQL/image/2021-09-02-00-50-45.png b/数据库/MySQL/image/2021-09-02-00-50-45.png new file mode 100644 index 00000000..2a3a377c Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-00-50-45.png differ diff --git a/数据库/MySQL/image/2021-09-02-00-51-00.png b/数据库/MySQL/image/2021-09-02-00-51-00.png new file mode 100644 index 00000000..45e6733b Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-00-51-00.png differ diff --git a/数据库/MySQL/image/2021-09-02-00-54-06.png b/数据库/MySQL/image/2021-09-02-00-54-06.png new file mode 100644 index 00000000..f6e43b5f Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-00-54-06.png differ diff --git a/数据库/MySQL/image/2021-09-02-00-54-18.png b/数据库/MySQL/image/2021-09-02-00-54-18.png new file mode 100644 index 00000000..023ccb40 Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-00-54-18.png differ diff --git a/数据库/MySQL/image/2021-09-02-10-11-38.png b/数据库/MySQL/image/2021-09-02-10-11-38.png new file mode 100644 index 00000000..373b1418 Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-10-11-38.png differ diff --git a/数据库/MySQL/image/2021-09-02-10-14-13.png b/数据库/MySQL/image/2021-09-02-10-14-13.png new file mode 100644 index 00000000..39cdfa41 Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-10-14-13.png differ diff --git a/数据库/MySQL/image/2021-09-02-10-15-31.png b/数据库/MySQL/image/2021-09-02-10-15-31.png new file mode 100644 index 00000000..256be4af Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-10-15-31.png differ diff --git a/数据库/MySQL/image/2021-09-02-10-16-47.png b/数据库/MySQL/image/2021-09-02-10-16-47.png new file mode 100644 index 00000000..cccf2430 Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-10-16-47.png differ diff --git a/数据库/MySQL/image/2021-09-02-10-17-53.png b/数据库/MySQL/image/2021-09-02-10-17-53.png new file mode 100644 index 00000000..ad1aa641 Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-10-17-53.png differ diff --git a/数据库/MySQL/image/2021-09-02-10-19-31.png b/数据库/MySQL/image/2021-09-02-10-19-31.png new file mode 100644 index 00000000..8c3ae0b3 Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-10-19-31.png differ diff --git a/数据库/MySQL/image/2021-09-02-12-05-03.png b/数据库/MySQL/image/2021-09-02-12-05-03.png new file mode 100644 index 00000000..c65d2d25 Binary files /dev/null and b/数据库/MySQL/image/2021-09-02-12-05-03.png differ diff --git a/数据库/MySQL/附录1 MySQL存储引擎.md b/数据库/MySQL/附录1 MySQL存储引擎.md index ba714ae8..f0147457 100644 --- a/数据库/MySQL/附录1 MySQL存储引擎.md +++ b/数据库/MySQL/附录1 MySQL存储引擎.md @@ -51,9 +51,8 @@ frm和MYI可以存放在不同的目录下。MYI文件用来存储索引,但 3. 压缩表。上面说到支持数据压缩,说明肯定也支持这个格式。在数据文件发生错误时候,可以使用check table工具来检查,而且还可以使用repair table工具来恢复。 ### 存储引擎的特点 -有一个重要的特点那就是不支持事务,但是这也意味着他的存储速度更快,如果你的读写操作允许有错误数据的话,只是追求速度,可以选择这个存储引擎。 +有一个重要的特点那就是**不支持事务**,但是这也意味着他的存储速度更快,如果你的读写操作允许有错误数据的话,只是追求速度,可以选择这个存储引擎。 -MyISAM存储引擎 MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事物。MyISAM主要特性有: @@ -65,7 +64,7 @@ MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓 4. 最大的键长度是1000字节,这也可以通过编译来改变,对于键长度超过250字节的情况,一个超过1024字节的键将被用上 -5. BLOB和TEXT列可以被索引 +5. **BLOB和TEXT列**可以被索引 6. NULL被允许在索引的列中,这个值占每个键的0~1个字节 @@ -81,18 +80,34 @@ MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓 12. VARCHAR和CHAR列可以多达64KB + +### 存储引擎的特点2 + +设计简单,数据以紧密格式存储。对于只读数据,或者表比较小、可以容忍修复操作,则依然可以使用它。 + +提供了大量的特性,包括压缩表、空间数据索引等。 + +不支持事务。 + +不支持行级锁,只能对整张表加锁,读取时会对需要读到的所有表加共享锁,写入时则对表加排它锁。但在表有读取操作的同时,也可以往表中插入新的记录,这被称为并发插入(CONCURRENT INSERT)。 + +可以手工或者自动执行检查和修复操作,但是和事务恢复以及崩溃恢复不同,可能导致一些数据丢失,而且修复操作是非常慢的。 + +如果指定了 DELAY_KEY_WRITE 选项,在每次修改执行完成时,不会立即将修改的索引数据写入磁盘,而是会写到内存中的键缓冲区,只有在清理键缓冲区或者关闭表的时候才会将对应的索引块写入磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机崩溃时会造成索引损坏,需要执行修复操作。 + + ## 2.2 InnoDB ### 存储引擎的特点 InnoDB是默认的数据库存储引擎,他的主要特点有: -> 对于InnoDB来说,最大的特点在于支持事务。但是这是以损失效率来换取的。 +> 对于InnoDB来说,最大的特点在于**支持事务**。但是这是以损失效率来换取的。 1. 可以通过自动增长列,方法是auto_increment。 2. 支持事务。默认的事务隔离级别为可重复度,通过MVCC(并发版本控制)来实现的。 3. 使用的锁粒度为行级锁,可以支持更高的并发; 4. 支持外键约束;外键约束其实降低了表的查询速度,但是增加了表之间的耦合度。 5. 配合一些热备工具可以支持在线热备份; -6. 在InnoDB中存在着缓冲管理,通过缓冲池,将索引和数据全部缓存起来,加快查询的速度; -7. 对于InnoDB类型的表,其数据的物理组织形式是聚簇表。所有的数据按照主键来组织。数据和索引放在一块,都位于B+数的叶子节点上; +6. 在InnoDB中存在着缓冲管理,通过**缓冲池**,将索引和数据全部缓存起来,加快查询的速度; +7. 对于InnoDB类型的表,其数据的物理组织形式是**聚簇表**。所有的数据按照主键来组织。数据和索引放在一块,都位于B+数的叶子节点上; ### 存储引擎的实现 当然InnoDB的存储表和索引也有下面两种形式: @@ -120,6 +135,18 @@ InnoDB是默认的数据库存储引擎,他的主要特点有: 5. InnoDB被用在众多需要高性能的大型数据库站点上。InnoDB不创建目录,使用InnoDB时,MySQL将在MySQL数据目录下创建一个名为ibdata1的10MB大小的自动扩展数据文件,以及两个名为ib_logfile0和ib_logfile1的5MB大小的日志文件 + +### 存储引擎的特点3 + +1. 是 MySQL 默认的事务型存储引擎,只有在需要它不支持的特性时,才考虑使用其它存储引擎。 + +2. 实现了四个标准的隔离级别,默认级别是可重复读(REPEATABLE READ)。在可重复读隔离级别下,通过多版本并发控制(MVCC)+ Next-Key Locking 防止幻影读。 + +3. 主索引是聚簇索引,在索引中保存了数据,从而避免直接读取磁盘,因此对查询性能有很大的提升。 +4. 内部做了很多优化,包括从磁盘读取数据时采用的可预测性读、能够加快读操作并且自动创建的自适应哈希索引、能够加速插入操作的插入缓冲区等。 +5. 支持真正的在线热备份。其它存储引擎不支持在线热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。 + + ## 2.3 Memory ### 存储引擎的实现 diff --git a/数据库/MySQL/附录2 MySql性能优化.md b/数据库/MySQL/附录2 MySql性能优化.md index 103e873c..7da735cf 100644 --- a/数据库/MySQL/附录2 MySql性能优化.md +++ b/数据库/MySQL/附录2 MySql性能优化.md @@ -1,4 +1,4 @@ -# 10个MySQL性能调优的方法 +# 性能调优 > 参考文献 > * [https://www.jb51.net/article/70111.htm](https://www.jb51.net/article/70111.htm) > * [https://www.cnblogs.com/jiekzou/p/5371085.html](https://www.cnblogs.com/jiekzou/p/5371085.html) @@ -8,86 +8,156 @@ 1. 数据库设计优化: 1. 选择合适的存储引擎 2. 设计合理的表结构(符合3NF) - 3. 添加适当索引(index) [四种: 普通索引、主键索引、唯一索引unique、全文索引] + 3. 添加适当索引(index) 普通索引、主键索引、唯一索引、全文索引、组合索引、覆盖索引。 2. 查询语句优化: - 1. 通过show status命令了解各种SQL的执行频率。 - 2. 定位执行效率较低的SQL语句-(重点select,记录慢查询) - 3. 通过explain分析低效率的SQL + 1. 遵守查询规范。 + 2. 分析日志:通过show status命令了解各种SQL的执行频率。定位执行效率较低的SQL语句(重点select,记录慢查询) + 3. explain分析低效率的SQL语句 3. 查询过程优化 1. 从内存中读取数据 2. 减少磁盘写入操作(更大的写缓存) - 3. 提高磁盘读取速度 -## 1 选择合适的存储引擎: InnoDB + 3. 提高磁盘读取速度(硬件设备改善) -* 除非你的数据表使用来做只读或者全文检索 (相信现在提到全文检索,没人会用 MYSQL 了),你应该默认选择 InnoDB 。 -* 你自己在测试的时候可能会发现 MyISAM 比 InnoDB 速度快,这是因为: MyISAM 只缓存索引,而 InnoDB 缓存数据和索引,MyISAM 不支持事务。但是 如果你使用 innodb_flush_log_at_trx_commit = 2 可以获得接近的读取性能 (相差百倍) 。 +## 1.1 存储引擎 +* 支持全文索引:MyISAM +* 支持外键:Innodb +* 支持缓存:Innodb +* 支持事务:Innodb +* 支持并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。 +* 支持备份:InnoDB 支持在线热备份。 +* 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。 +* 其它特性:MyISAM 支持压缩表和空间数据索引。 -### 1.1 如何将现有的 MyISAM 数据库转换为 InnoDB: +## 1.2 表结构 +符合3BNF/EBNF范式 +* 属性不可分 +* 非主属性依赖完全的主属性 +* 非主属性不依赖其他的非主属性 +* 消除多值依赖(多对多关系) +## 1.3 添加索引 +索引类型选择: +1. **前缀索引**。对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。前缀长度的选取需要根据索引选择性来确定。字符串列加索引最好加短索引,即对前该列的前xx个字符,例如:key 'ind_user_info_addr' (addr(10)) USINGBTREE代表对addr列的前10个字符家索引。 +2. **复合索引**。在需要使用多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好。如果创建了一个(username,age,addr)的复合索引,那么相当于创建了(username,age,addr),(username,age),(username)三个索引,所以在创建复合索引的时候应该将最常用的限制条件的列放在最左边,依次递减。 + +索引使用规范: +1. 不能再索引字段上计算。会导致索引无效,成为全表扫描。 +2. 将非”索引”数据分离,比如将大篇文章分离存储,不影响其他自动查询。 +3. **覆盖索引**。能够直接通过索引查询到所需要的字段,不需要通过回表查询,找到数据。 +4. **关联查询**。保证关联的字段都建立索引,并且字段类型一致,这样才能两个表都使用索引。如果字段类型不一样,至少一个表不能使用索引。保证连接的索引是相同类型。即a.age = b.age,a表的和b表的age字段类型保证一样,并且都建立了索引。 +5. **最左匹配原则**:索引列如果使用like条件进行查询,那么 like 'xxx%' 可以使用索引,like '%xxx' 不能使用索引。 +6. 索引列的值最好不要有null值。列中只要包含null,则不会被包含到索引中,复合索引中只要有一列为null值,则这个复合索引失效的。所以创建索引列不要设置默认值null +7. 如果where条件中使用了一个列的索引,那么后面order by 在用这个列进行排序时,便不会再使用索引。where条件用到复合索引中的字段时,最好把该字段放在复合索引的左端,这样才能使用索引提高查询。 +8. 排序索引。尽量不要使用包含多个列的排序,如果需要则给这些列加上复合索引。 + + + +## 2.1 查询规范 + +1. **减少请求的数据量**。单条查询最后增加 LIMIT,停止全表扫描。 + - 只返回必要的列:最好不要使用 SELECT * 语句。 + - 只返回必要的行:使用 LIMIT 语句来限制返回的数据。 +3. 不用 MYSQL 内置的函数,因为内置函数不会建立查询缓存。 +4. inner join 内连接也叫做等值连接,left/right join 是外连接。能用inner join连接的尽量用inner join连接 +5. 尽量使用外连接来替换子查询。在使用on和where的时候,先用on,在用where。使用join时,用小的结果驱动大的结果(left join左表结果尽量小,如果有条件,先放左边处理,right join同理反向)。多表联合查询尽量拆分多个简单的sql语句进行查询。 +6. 尽量不要使用BY RAND()命令。减少排序order by。少用OR。尽量不要使用not in 和<> 操作 +7. 避免类型转换,也就是转入的参数类型要和字段类型一致。 +8. 不要在列上进行运算。 +9. 使用批量插入操作代替一个一个插入 +10. 对于多表查询可以建立视图。 + + + +## 2.2 分析日志 +修改mysql的慢查询. ``` -mysql -u [USER_NAME] -p -e "SHOW TABLES IN [DATABASE_NAME];" | tail -n +2 | xargs -I '{}' echo "ALTER TABLE {} ENGINE=InnoDB;" > alter_table.sql - -perl -p -i -e 's/(search_[a-z_]+ ENGINE=)InnoDB//1MyISAM/g' alter_table.sql - -mysql -u [USER_NAME] -p [DATABASE_NAME] < alter_table.sql - -mysql -u [USER_NAME] -p -e "SHOW TABLES IN [DATABASE_NAME];" | tail -n +2 | xargs -I '{}' echo "ALTER TABLE {} ENGINE=InnoDB;" > alter_table.sql - -perl -p -i -e 's/(search_[a-z_]+ ENGINE=)InnoDB//1MyISAM/g' alter_table.sql - -mysql -u [USER_NAME] -p [DATABASE_NAME] < alter_table.sql +show variables like 'long_query_time' ; //可以显示当前慢查询时间 +set long_query_time=1 ;//可以修改慢查询时间 ``` -### 1.2 为每个表分别创建 InnoDB FILE: - +记录所有查询,这在用 ORM 系统或者生成查询语句的系统很有用。 ``` -innodb_file_per_table=1 +log=/var/log/mysql.log ``` -这样可以保证 ibdata1 文件不会过大,失去控制。尤其是在执行 mysqlcheck -o –all-databases 的时候。 +注意不要在生产环境用,否则会占满你的磁盘空间。 - - -## 2. 保证从内存中读取数据,讲数据保存在内存中 - -### 2.1 足够大的 innodb_buffer_pool_size - -推荐将数据完全保存在 innodb_buffer_pool_size ,即按存储量规划 innodb_buffer_pool_size 的容量。这样你可以完全从内存中读取数据,最大限度减少磁盘操作。 - -第一步:如何确定 innodb_buffer_pool_size 足够大,数据是从内存读取而不是硬盘? - -查询buffer size +记录执行时间超过 1 秒的查询: ``` -mysql> SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool_pages_%'; -+----------------------------------+--------+ -| Variable_name | Value | -+----------------------------------+--------+ -| Innodb_buffer_pool_pages_data | 129037 | -| Innodb_buffer_pool_pages_dirty | 362 | -| Innodb_buffer_pool_pages_flushed | 9998 | -| Innodb_buffer_pool_pages_free | 0 | !!!!!!!! -| Innodb_buffer_pool_pages_misc | 2035 | -| Innodb_buffer_pool_pages_total | 131072 | -+----------------------------------+--------+ -6 rows in set (0.00 sec) - -innodb_additional_mem_pool_size = 1/200 of buffer_pool -innodb_max_dirty_pages_pct 80% +long_query_time=1 +log-slow-queries=/var/log/mysql/log-slow-queries.log ``` -发现 Innodb_buffer_pool_pages_free 为 0,则说明 buffer pool 已经被用光,需要增大 innodb_buffer_pool_size -或者用iostat -d -x -k 1 命令,查看硬盘的操作。 - -第二步:服务器上是否有足够内存用来规划。执行 echo 1 > /proc/sys/vm/drop_caches 清除操作系统的文件缓存,可以看到真正的内存使用量。 - -### 2.2 数据预热 - -默认情况,只有某条数据被读取一次,才会缓存在 innodb_buffer_pool。所以,数据库刚刚启动,需要进行数据预热,将磁盘上的所有数据缓存到内存中。数据预热可以提高读取速度。 - -对于 InnoDB 数据库,可以用以下方法,进行数据预热: - -1. 将以下脚本保存为 MakeSelectQueriesToLoad.sql +## 2.3 explain分析查询 +### 分析方法 ``` +Explain select * from emp where ename=“wsrcla” +``` +会产生如下信息: + +* select_type:表示查询的类型。 +* table:输出结果集的表 +* type:表示表的连接类型 +* possible_keys:表示查询时,可能使用的索引 +* key:表示实际使用的索引 +* key_len:索引字段的长度 +* rows:扫描出的行数(估算的行数) +* Extra:执行情况的描述和说明 + +### 重构查询方式 + +#### 1. 切分大查询 + +一个大查询如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。 + +```sql +DELETE FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH); +``` + +```sql +rows_affected = 0 +do { + rows_affected = do_query( + "DELETE FROM messages WHERE create < DATE_SUB(NOW(), INTERVAL 3 MONTH) LIMIT 10000") +} while rows_affected > 0 +``` + +#### 2. 分解大连接查询 + +将一个大连接查询分解成对每一个表进行一次单表查询,然后在应用程序中进行关联,这样做的好处有: + +- 让缓存更高效。对于连接查询,如果其中一个表发生变化,那么整个查询缓存就无法使用。而分解后的多个查询,即使其中一个表发生变化,对其它表的查询缓存依然可以使用。 +- 分解成多个单表查询,这些单表查询的缓存结果更可能被其它查询使用到,从而减少冗余记录的查询。 +- 减少锁竞争; +- 在应用层进行连接,可以更容易对数据库进行拆分,从而更容易做到高性能和可伸缩。 +- 查询本身效率也可能会有所提升。例如下面的例子中,使用 IN() 代替连接查询,可以让 MySQL 按照 ID 顺序进行查询,这可能比随机的连接要更高效。 + +```sql +SELECT * FROM tag +JOIN tag_post ON tag_post.tag_id=tag.id +JOIN post ON tag_post.post_id=post.id +WHERE tag.tag='mysql'; +``` + +```sql +SELECT * FROM tag WHERE tag='mysql'; +SELECT * FROM tag_post WHERE tag_id=1234; +SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904); +``` + + + +## 3.1 内存读取 + +### 增大缓存 +* 将更新操作先记录在change buffer,减少读磁盘,语句的执行速度会得到明显的提升。而且,数据读入内存是需要占用buffer pool的,所以这种方式还能够避免占用内存,提高内存利用率 +* innodb_buffer_pool_size。将数据完全保存在 innodb_buffer_pool中。可以完全从内存中读取数据,最大限度减少磁盘操作。 + +### 数据预热 + +默认情况,只有某条数据被读取一次,才会缓存在 innodb_buffer_pool。数据库启动后,需要进行数据预热,将磁盘上的所有数据缓存到内存中。数据预热可以提高读取速度。 + +```sql SELECT DISTINCT CONCAT('SELECT ',ndxcollist,' FROM ',db,'.',tb, ' ORDER BY ',ndxcollist,';') SelectQueryToLoadCache @@ -115,157 +185,34 @@ SELECT DISTINCT ) AA ORDER BY db,tb; ``` -2. 执行 -``` -mysql -uroot -AN < /root/MakeSelectQueriesToLoad.sql > /root/SelectQueriesToLoad.sql -``` -3. 每次重启数据库,或者整库备份前需要预热的时候执行: -``` -mysql -uroot < /root/SelectQueriesToLoad.sql > /dev/null 2>&1 -``` -### 2.3 不要让数据存到 SWAP 中 -如果是专用 MYSQL 服务器,可以禁用 SWAP,如果是共享服务器,确定 innodb_buffer_pool_size 足够大。或者使用固定的内存空间做缓存,使用 memlock 指令。 - +## 3.2 减少磁盘读写 -## 3 定期优化重建数据库 +### 使用足够大的写入缓存innodb_log_file_size -mysqlcheck -o –all-databases 会让 ibdata1 不断增大,真正的优化只有重建数据表结构: -``` -CREATE TABLE mydb.mytablenew LIKE mydb.mytable; -INSERT INTO mydb.mytablenew SELECT * FROM mydb.mytable; -ALTER TABLE mydb.mytable RENAME mydb.mytablezap; -ALTER TABLE mydb.mytablenew RENAME mydb.mytable; -DROP TABLE mydb.mytablezap; -``` +* 如果用 1G 的 innodb_log_file_size ,假如服务器当机,需要 10 分钟来恢复。 +* 推荐 innodb_log_file_size 设置为 0.25 * innodb_buffer_pool_size -## 4 减少磁盘写入操作 - -### 4.1 使用足够大的写入缓存 innodb_log_file_size - -但是需要注意如果用 1G 的 innodb_log_file_size ,假如服务器当机,需要 10 分钟来恢复。 - -推荐 innodb_log_file_size 设置为 0.25 * innodb_buffer_pool_size - -### 4.2 innodb_flush_log_at_trx_commit +### innodb_flush_log_at_trx_commit 这个选项和写磁盘操作密切相关: - +```sql innodb_flush_log_at_trx_commit = 1 则每次修改写入磁盘 innodb_flush_log_at_trx_commit = 0/2 每秒写入磁盘 - -如果你的应用不涉及很高的安全性 (金融系统),或者基础架构足够安全,或者 事务都很小,都可以用 0 或者 2 来降低磁盘操作。 - -### 4.3 避免双写入缓冲 ``` -innodb_flush_method=O_DIRECT -``` +如果你的应用不涉及很高的安全性 (金融系统),或者基础架构足够安全,或者事务都很小,都可以用 0 或者 2 来降低磁盘操作。 -## 5 提高磁盘读写速度 -RAID0 尤其是在使用 EC2 这种虚拟磁盘 (EBS) 的时候,使用软 RAID0 非常重要。 - - - -## 6 充分使用索引 - -### 6.1 查看现有表结构和索引 -``` -SHOW CREATE TABLE db1.tb1/G -``` -### 6.2 添加必要的索引 - -索引是提高查询速度的唯一方法,比如搜索引擎用的倒排索引是一样的原理。 - -索引的添加需要根据查询来确定,比如通过慢查询日志或者查询日志,或者通过 EXPLAIN 命令分析查询。 - -``` -ADD UNIQUE INDEX -ADD INDEX -``` - -### 6.3 实例:优化用户验证表: -添加索引 - -``` -ALTER TABLE users ADD UNIQUE INDEX username_ndx (username); -ALTER TABLE users ADD UNIQUE INDEX username_password_ndx (username,password); -``` -每次重启服务器进行数据预热 -``` -echo “select username,password from users;” > /var/lib/mysql/upcache.sql -``` -添加启动脚本到 my.cnf -``` -[mysqld] -init-file=/var/lib/mysql/upcache.sql -``` -### 6.4 实例:使用自动加索引的框架或者自动拆分表结构的框架 -比如,Rails 这样的框架,会自动添加索引,Drupal 这样的框架会自动拆分表结构。会在你开发的初期指明正确的方向。所以,经验不太丰富的人一开始就追求从 0 开始构建,实际是不好的做法。 - -## 7 分析查询日志和慢查询日志 -修改mysql的慢查询. -``` -show variables like 'long_query_time' ; //可以显示当前慢查询时间 -set long_query_time=1 ;//可以修改慢查询时间 -``` -记录所有查询,这在用 ORM 系统或者生成查询语句的系统很有用。 -``` -log=/var/log/mysql.log -``` -注意不要在生产环境用,否则会占满你的磁盘空间。 - -记录执行时间超过 1 秒的查询: -``` -long_query_time=1 -log-slow-queries=/var/log/mysql/log-slow-queries.log -``` - -### explain查询语句 - -Explain select * from emp where ename=“wsrcla” -会产生如下信息: -select_type:表示查询的类型。 -table:输出结果集的表 -type:表示表的连接类型 -possible_keys:表示查询时,可能使用的索引 -key:表示实际使用的索引 -key_len:索引字段的长度 -rows:扫描出的行数(估算的行数) -Extra:执行情况的描述和说明 - -## 8 激进的方法,使用内存磁盘 - -现在基础设施的可靠性已经非常高了,比如 EC2 几乎不用担心服务器硬件当机。而且内存实在是便宜,很容易买到几十G内存的服务器,可以用内存磁盘,定期备份到磁盘。 - -将 MYSQL 目录迁移到 4G 的内存磁盘 -``` -mkdir -p /mnt/ramdisk -sudo mount -t tmpfs -o size=4000M tmpfs /mnt/ramdisk/ -mv /var/lib/mysql /mnt/ramdisk/mysql -ln -s /tmp/ramdisk/mysql /var/lib/mysql -chown mysql:mysql mysql -``` -## 9 用 NOSQL 的方式使用 MYSQL - -B-TREE 仍然是最高效的索引之一,所有 MYSQL 仍然不会过时。 - -用 HandlerSocket 跳过 MYSQL 的 SQL 解析层,MYSQL 就真正变成了 NOSQL。 - -## 10 其他 - -1. 单条查询最后增加 LIMIT 1,停止全表扫描。 -2. 将非”索引”数据分离,比如将大篇文章分离存储,不影响其他自动查询。 -3. 不用 MYSQL 内置的函数,因为内置函数不会建立查询缓存。 -4. PHP 的建立连接速度非常快,所有可以不用连接池,否则可能会造成超过连接数。当然不用连接池 PHP 程序也可能将 -5. 连接数占满比如用了 @ignore_user_abort(TRUE); -6. 使用 IP 而不是域名做数据库路径,避免 DNS 解析问题 +## 3.3 提高磁盘读取速度 +## 4 其他原则 -”建立合理索引”(什么样的索引合理?) “ -分表分库”(用什么策略分表分库?) -“主从分离”(用什么中间件?) \ No newline at end of file +1. 不在数据库做运算:cpu计算务必移至业务层 +1. 控制单表数据量:单表记录控制在1000w +1. 控制列数量:字段数控制在20以内 +1. 平衡范式与冗余:为提高效率牺牲范式设计,冗余数据 +1. 拒绝3B:拒绝大sql,大事物,大批量 \ No newline at end of file diff --git a/数据库/MySQL/附录3 MySQL索引类型.md b/数据库/MySQL/附录3 MySQL索引类型.md index 01a52bc0..6e0fb4cb 100644 --- a/数据库/MySQL/附录3 MySQL索引类型.md +++ b/数据库/MySQL/附录3 MySQL索引类型.md @@ -125,9 +125,27 @@ CREATE FULLTEXT INDEX index_content ON article(content) ``` ### 覆盖索引 +索引包含所有需要查询的字段的值。 + * 覆盖索引,select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。 * 这个时候,可以不用访问指定的数据。也就不需要回表查询具体的数据,通过索引即可得到想要的数据。 + + +具有以下优点: + +- 索引通常远小于数据行的大小,只读取索引能大大减少数据访问量。 +- 一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。 +- 对于 InnoDB 引擎,若辅助索引能够覆盖查询,则无需访问主索引。 + + +### 索引优点 + +- 大大减少了服务器需要扫描的数据行数。 + +- 帮助服务器避免进行排序和分组,以及避免创建临时表(B+Tree 索引是有序的,可以用于 ORDER BY 和 GROUP BY 操作。临时表主要是在排序和分组过程中创建,不需要排序和分组,也就不需要创建临时表)。 + +- 将随机 I/O 变为顺序 I/O(B+Tree 索引是有序的,会将相邻的数据都存储在一起)。 ### 索引缺点 1. 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行insert、update和delete。因为更新表时,不仅要保存数据,还要保存一下索引文件。 @@ -183,4 +201,9 @@ select username, score from t1 where username = '小明' ### 前缀索引 * tire索引/前缀索引:用来索引字符串。 -> 特点:索引能够加快数据库查询,需要占用一定的存储空间。基本表更新后,索引也需要更新。用户不必显示地选择索引,关系数据库管理系统在执行查询时,会自动选择合适的索引作为存储路径。 \ No newline at end of file + +> 特点:索引能够加快数据库查询,需要占用一定的存储空间。基本表更新后,索引也需要更新。用户不必显示地选择索引,关系数据库管理系统在执行查询时,会自动选择合适的索引作为存储路径。 + + +> MySQL中常用的索引结构有:B+树索引和哈希索引两种。目前建表用的B+树索引就是BTREE索引。 +> 在MySQL中,MyISAM和InnoDB两种存储引擎都不支持哈希索引。只有HEAP/MEMORY引擎才能显示支持哈希索引。 diff --git a/数据库/MySQL/附录5 MySQL连接查询.md b/数据库/MySQL/附录5 MySQL连接查询.md index 3abb7c2a..15c8a952 100644 --- a/数据库/MySQL/附录5 MySQL连接查询.md +++ b/数据库/MySQL/附录5 MySQL连接查询.md @@ -1,4 +1,4 @@ -# JOIN连接查询 +# 5 JOIN连接查询 > 参考文献 > * [MySQL的JOIN用法](https://www.cnblogs.com/hcfinal/p/10231694.html) diff --git a/数据库/MySQL/附录6 MySQL分库分表.md b/数据库/MySQL/附录6 MySQL分库分表.md index ddb601fb..eb6d7634 100644 --- a/数据库/MySQL/附录6 MySQL分库分表.md +++ b/数据库/MySQL/附录6 MySQL分库分表.md @@ -1,360 +1,41 @@ -# MySQL - -* [MySQL](#mysql) - * [一、索引](#一索引) - * [B+ Tree 原理](#b-tree-原理) - * [MySQL 索引](#mysql-索引) - * [索引优化](#索引优化) - * [索引的优点](#索引的优点) - * [索引的使用条件](#索引的使用条件) - * [二、查询性能优化](#二查询性能优化) - * [使用 Explain 进行分析](#使用-explain-进行分析) - * [优化数据访问](#优化数据访问) - * [重构查询方式](#重构查询方式) - * [三、存储引擎](#三存储引擎) - * [InnoDB](#innodb) - * [MyISAM](#myisam) - * [比较](#比较) - * [四、数据类型](#四数据类型) - * [整型](#整型) - * [浮点数](#浮点数) - * [字符串](#字符串) - * [时间和日期](#时间和日期) - * [五、切分](#五切分) - * [水平切分](#水平切分) - * [垂直切分](#垂直切分) - * [Sharding 策略](#sharding-策略) - * [Sharding 存在的问题](#sharding-存在的问题) - * [六、复制](#六复制) - * [主从复制](#主从复制) - * [读写分离](#读写分离) - * [参考资料](#参考资料) - +# MySQL分库分表和主从分离 +## 1 概述 -## 一、索引 +### 分库分表的原因 -### B+ Tree 原理 +当一张表的数据达到几千万时,查询一次所花的时间会变多,如果有联合查询的话,有可能会死在那儿了。分表的目的就在于此,减小数据库的负担,缩短查询时间。 +* 用户请求量太大。因为单服务器TPS,内存,IO都是有限的。解决方法:分散请求到多个服务器上; 其实用户请求和执行一个sql查询是本质是一样的,都是请求一个资源,只是用户请求还会经过网关,路由,http服务器等。 -#### 1. 数据结构 +* 单库太大。单个数据库处理能力有限;单库所在服务器上磁盘空间不足;单库上操作的IO瓶颈 解决方法:切分成更多更小的库 -B Tree 指的是 Balance Tree,也就是平衡树。平衡树是一颗查找树,并且所有叶子节点位于同一层。 +* 单表太大。CRUD都成问题;索引膨胀,查询超时。解决方法:切分成多个数据集更小的表。 -B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具有 B Tree 的平衡性,并且通过顺序访问指针来提高区间查询的性能。 +### 分库分表的形式 -在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1,且不为 null,则该指针指向节点的所有 key 大于等于 keyi 且小于等于 keyi+1。 +* 单库单表。单库单表是最常见的数据库设计,例如,有一张用户(user)表放在数据库db中,所有的用户都可以在db库中的user表中查到。 -