MySQL高级和原理
MySQL高级
字符
- my.cnf配置文件最后加上
character_set_server=utf8
- 修改表的字符集
mysql> alter table dubbo convert to character set 'utf8';
权限
查看权限
mysql> select * from user\G;
*************************** 1. row ***************************
Host: localhost
User: root
Password:
Select_priv: Y
Insert_priv: Y
Update_priv: Y
Delete_priv: Y
Create_priv: Y
Drop_priv: Y
Reload_priv: Y
Shutdown_priv: Y
Process_priv: Y
File_priv: Y
Grant_priv: Y
References_priv: Y
Index_priv: Y
Alter_priv: Y
Show_db_priv: Y
Super_priv: Y
Create_tmp_table_priv: Y
Lock_tables_priv: Y
Execute_priv: Y
Repl_slave_priv: Y
Repl_client_priv: Y
Create_view_priv: Y
Show_view_priv: Y
Create_routine_priv: Y
Alter_routine_priv: Y
Create_user_priv: Y
Event_priv: Y
Trigger_priv: Y
Create_tablespace_priv: Y
ssl_type:
ssl_cipher:
x509_issuer:
x509_subject:
max_questions: 0
max_updates: 0
max_connections: 0
max_user_connections: 0
plugin: mysql_native_password
authentication_string:
password_expired: N
创建用户权限
grant all privileges on *.*to root@'%' identified by '123';
百分号表示所有远程访问ip都允许。给所有表所有库的所有权限。
group by 注意事项
group by使用原则:select 后面只能放函数和 group by 后的字段
mysql> show variables like 'sql_mode';
+---------------+--------------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------------+
| sql_mode | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION |
+---------------+--------------------------------------------+
1 row in set (0.00 sec)
如果数据库的 sql_mod 有 ONLY_FULL_GROUP_BY,必须遵守group by原则。group by使用原则:select 后面只能放函数和 group by 后的字段
MySQL架构
架构图
-
Client :
提供连接MySQL服务器功能的常用工具集 -
Server :
MySQL实例,真正提供数据存储和数据处理功能的MySQL服务器进程 -
mysqld:
MySQL服务器守护程序,在后台运行。它管理着客户端请求。mysqld是一个多线程的进程,允许多个会话连接,端口监听连接,管理MySQL实例 -
MySQL memory allocation:
MySQL的要求的内存空间是动态的,比如innodb_buffer_pool_size (from 5.7.5), key_buffer_size
。每个会话都有独一无二的执行计划,我们只能共享同一会话域内的数据集。 -
SESSION
为每个客户端连接分配一个会话,动态分配和回收。用于查询处理,每个会话同时具备一个缓冲区。每个会话是作为一个线程执行的 -
Parser
检测SQL语句语法,为每条SQL语句生成SQL_ID
,用户认证也发生在这个阶段 -
Optimizer
创造一个有效率的执行计划(根据具体的存储引擎)。它将会重写查询语句。比如:InnoDB有共享缓冲区,所以,优化器会首先从预先缓存的数据中提取。使用 table statistics optimizer将会为SQL查询生成一个执行计划。用户权限检查也发生在这个阶段。 -
Metadata cache
缓存对象元信息和统计信息 -
Query cache
共享在内存中的完全一样的查询语句。如果完全相同的查询在缓存命中,MySQL服务器会直接从缓存中去检索结果。缓存是会话间共享的,所以为一个客户生成的结果集也能为另一个客户所用。查询缓存基于SQL_ID
。将SELECT语句写入视图就是查询缓存最好的例子。 -
key cache
缓存表索引。MySQL keys
是索引。如果索引数据量小,它将缓存索引结构和叶子节点(存储索引数据)。如果索引很大,它只会缓存索引结构,通常供MyISAM存储引擎使用
查看执行计划
设置 profiling
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| have_profiling | YES |
| profiling | OFF |
| profiling_history_size | 15 |
+------------------------+-------+
3 rows in set (0.01 sec)
mysql> set profiling = 1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show variables like '%profiling%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| have_profiling | YES |
| profiling | ON |
| profiling_history_size | 15 |
+------------------------+-------+
3 rows in set (0.00 sec)
mysql> show profiles;
+----------+------------+-----------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------------+
| 1 | 0.00206750 | show variables like '%profiling%' |
+----------+------------+-----------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> show profile cpu,block io for query 1;
+----------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+----------------------+----------+----------+------------+--------------+---------------+
| starting | 0.000106 | 0.000034 | 0.000058 | 0 | 0 |
| checking permissions | 0.000060 | 0.000023 | 0.000037 | 0 | 0 |
| Opening tables | 0.000076 | 0.000028 | 0.000048 | 0 | 0 |
| init | 0.000041 | 0.000015 | 0.000026 | 0 | 0 |
| System lock | 0.000050 | 0.000019 | 0.000031 | 0 | 0 |
| optimizing | 0.000038 | 0.000016 | 0.000027 | 0 | 0 |
| statistics | 0.000583 | 0.000000 | 0.000579 | 0 | 0 |
| preparing | 0.000045 | 0.000000 | 0.000044 | 0 | 0 |
| executing | 0.000498 | 0.000000 | 0.000499 | 0 | 0 |
| Sending data | 0.000211 | 0.000210 | 0.000000 | 0 | 0 |
| end | 0.000035 | 0.000034 | 0.000000 | 0 | 0 |
| query end | 0.000049 | 0.000050 | 0.000000 | 0 | 0 |
| closing tables | 0.000035 | 0.000034 | 0.000000 | 0 | 0 |
| removing tmp table | 0.000037 | 0.000037 | 0.000000 | 0 | 0 |
| closing tables | 0.000034 | 0.000034 | 0.000000 | 0 | 0 |
| freeing items | 0.000099 | 0.000099 | 0.000000 | 0 | 0 |
| cleaning up | 0.000071 | 0.000071 | 0.000000 | 0 | 0 |
+----------------------+----------+----------+------------+--------------+---------------+
17 rows in set, 1 warning (0.00 sec)
对比前后两次查询sql执行周期:
mysql> select * from Scores;
// 结果省略
10 rows in set (0.01 sec)
mysql> select * from Scores;
//结果省略
10 rows in set (0.00 sec)
mysql> show profiles;
+----------+------------+-----------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------------+
| 1 | 0.00206750 | show variables like '%profiling%' |
| 2 | 0.00197800 | show variables like '%profiling%' |
| 3 | 0.00091250 | select * from Scores |
| 4 | 0.00170050 | SELECT DATABASE() |
| 5 | 0.00155175 | show databases |
| 6 | 0.00076800 | show tables |
| 7 | 0.00330450 | select * from Scores |
| 8 | 0.00066800 | select * from Scores |
+----------+------------+-----------------------------------+
8 rows in set, 1 warning (0.00 sec)
mysql> show profile cpu,block io for query 7;
+--------------------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+--------------------------------+----------+----------+------------+--------------+---------------+
| starting | 0.000065 | 0.000018 | 0.000042 | 0 | 0 |
| Waiting for query cache lock | 0.000032 | 0.000009 | 0.000022 | 0 | 0 |
| init | 0.000032 | 0.000009 | 0.000023 | 0 | 0 |
| checking query cache for query | 0.000072 | 0.000022 | 0.000051 | 0 | 0 |
| checking permissions | 0.000036 | 0.000010 | 0.000024 | 0 | 0 |
| Opening tables | 0.000227 | 0.000230 | 0.000000 | 0 | 0 |
| init | 0.000069 | 0.000075 | 0.000000 | 0 | 0 |
| System lock | 0.000133 | 0.000126 | 0.000000 | 0 | 0 |
| Waiting for query cache lock | 0.000036 | 0.000033 | 0.000000 | 0 | 0 |
| System lock | 0.000054 | 0.000063 | 0.000000 | 0 | 0 |
| optimizing | 0.000048 | 0.000039 | 0.000000 | 0 | 0 |
| statistics | 0.000049 | 0.000054 | 0.000000 | 0 | 0 |
| preparing | 0.000054 | 0.000049 | 0.000000 | 0 | 0 |
| executing | 0.000034 | 0.000162 | 0.000000 | 0 | 0 |
| Sending data | 0.001851 | 0.001726 | 0.000000 | 0 | 0 |
| end | 0.000044 | 0.000040 | 0.000000 | 0 | 0 |
| query end | 0.000040 | 0.000039 | 0.000000 | 0 | 0 |
| closing tables | 0.000072 | 0.000072 | 0.000000 | 0 | 0 |
| freeing items | 0.000052 | 0.000052 | 0.000000 | 0 | 0 |
| Waiting for query cache lock | 0.000032 | 0.000031 | 0.000000 | 0 | 0 |
| freeing items | 0.000105 | 0.000105 | 0.000000 | 0 | 0 |
| Waiting for query cache lock | 0.000032 | 0.000032 | 0.000000 | 0 | 0 |
| freeing items | 0.000031 | 0.000031 | 0.000000 | 0 | 0 |
| storing result in query cache | 0.000033 | 0.000033 | 0.000000 | 0 | 0 |
| cleaning up | 0.000076 | 0.000076 | 0.000000 | 0 | 0 |
+--------------------------------+----------+----------+------------+--------------+---------------+
25 rows in set, 1 warning (0.00 sec)
mysql> show profile cpu,block io for query 8;
+--------------------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+--------------------------------+----------+----------+------------+--------------+---------------+
| starting | 0.000068 | 0.000019 | 0.000045 | 0 | 0 |
| Waiting for query cache lock | 0.000037 | 0.000026 | 0.000061 | 0 | 0 |
| init | 0.000315 | 0.000000 | 0.000267 | 0 | 0 |
| checking query cache for query | 0.000045 | 0.000000 | 0.000040 | 0 | 0 |
| checking privileges on cached | 0.000033 | 0.000000 | 0.000033 | 0 | 0 |
| checking permissions | 0.000047 | 0.000000 | 0.000049 | 0 | 0 |
| sending cached result to clien | 0.000077 | 0.000000 | 0.000074 | 0 | 0 |
| cleaning up | 0.000048 | 0.000000 | 0.000048 | 0 | 0 |
+--------------------------------+----------+----------+------------+--------------+---------------+
8 rows in set, 1 warning (0.00 sec)
上述能证明命中了缓存。命中缓行的条件得是:SQL语句一摸一样。
引擎
外键:数据多的时候,初始化数据很麻烦(数据错误,很难批量插入数据)
使用 show engines; 来查询所有的引擎
对比项 | MyISAM | InnoDB |
---|---|---|
外键 | 不支持 | 支持 |
事务 | 不支持 | 支持 |
行表锁 | 表锁,不适合高并发 | 行锁,适合高并发 |
缓存 | 只缓存索引,不缓存数据 | 不仅缓存索引还要缓存真实数据,对内存要求较高,而且内存大小对性能有决定性影响 |
关注 | 节省资源 | 并发写,事务,更大资源 |
系统自带表 | 使用 | 不使用 |
-
Archive 引擎,适合日志和数据采集,比innodb小83%
-
Memory引擎,一般用redis替代
索引
join 复习
- 数据过多 - 分库分表
- 关联太多表,太多 join - sql优化
- 没有充分利用索引 - 索引建立
- 服务器参数调优 - 调整my.cnf
左连接 where后加 B.key is not null 能选出差集
select * from A a left join B b on a.id = b.id where b.id is not null
MySQL单表极限500w
索引是啥
是帮助mysql高级获取数据的数据结构,排好序的快速查找数据结构。一般来说索引也很大,会以索引文件的形式放在存储的磁盘上。增删改也会修改索引,导致开销变大。
索引分类
- 单值索引:一个索引只包含单个列
- 唯一索引:索引列的值必须唯一,但是允许有空
- 复合索引:一个索引包含多个列
Mysql 索引结构
- BTree索引:传统二叉树,每个节点(两个数据和三个数据指针)为一个磁盘块,每个节点的读取就是一次 IO,所以查询 IO 次数 = 树的高度。因此B+树以更短的层数,减少IO次数。IO次数是最耗时的。
- Hash索引
- full-text全文索引
- R-Tree索引
索引优势
提高检索效率,降低数据库 IO 成本,通过索引对数据库数据进行排序,降低CPU负载,索引本身也是一张表,KV存储。
二叉树正常情况下是平衡二叉树,但是如果极端情况下(一直比现在节点大,导致一直插入再右节点下,会退化成单链表)B-Tree 平衡树,会自动平衡,避免上述情况,每个树节点包含数据在磁盘中的位置,还有三个向下的指针。(B+树,本身不存储指向数据的指针,叶子节点才会包含指向磁盘数据的指针。由于B+树没有带上指向数据的指针,所以它每个节点内存占用更少,同等内存可以获取到更多的B+树节点,能更快比较出磁盘位置。B树的缺页率会更高,增加额外的 IO 开销) 这段话我觉得不好,下面更好:(传统二叉树,每个节点(两个数据和三个数据指针)为一个磁盘块,每个节点的读取就是一次 IO,所以查询 IO 次数 = 树的高度。因此B+树以更短的层数,减少IO次数。IO次数是最耗时的)
聚簇索引 & 非聚簇索引
- 聚簇索引:数据和索引在一起。索引本身能范围查找,比如找到 1 的索引和 5 的索引,那么直接能定位到 2 - 4 的索引。主键索引是 聚簇索引,其他都是 非聚簇索引。
- 非聚簇索引:即使找到 1 和 5 的索引,还是不能找到 2 - 4 的索引。
mysql> show index from major \G;
*************************** 1. row ***************************
Table: major
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
mysql> create index idx_Name on Socres(Name);
ERROR 1146 (42S02): Table 'demo.Socres' doesn't exist
mysql> create index idx_Name on Scores(Name);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from Scores \G;
*************************** 1. row ***************************
Table: Scores
Non_unique: 1
Key_name: idx_Name
Seq_in_index: 1
Column_name: Name
Collation: A
Cardinality: 8
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
// 还可以创建组合索引,性价比更高
mysql> create index idx on Person(Id_P, LastName, Address);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
适合建索引:
- 主键自动建立唯一索引
- 频繁作为查询条件的字段应该建立索引
- 查询中与其他表关联的字段,外键关系建立索引
- 组合索引性价比更高
- 查询中排序的字段,排序字段如果通过索引去访问提高排序速度
- 查询中统计或者分组字段(group by 包含了一个 order by)
不适合建索引:
- 表记录太少
- 经常增删改的字段
- Where里面用不到的字段
- 过滤性不好的字段
Explain
mysql> explain select * from (select * from Person as P) as P;
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 5 | NULL |
| 2 | DERIVED | P | ALL | NULL | NULL | NULL | NULL | 5 | NULL |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
2 rows in set (0.00 sec)
id相同,执行顺序自上到下,id不同的时候,先执行大的id。id号每个号码,表示一趟独立的查询,一个sql的查询趟数越少越好。
- simple:简单的select查询,没有子查询或union
- primary:主查询,含有子查询
- derived:衍生子查询
- subquery:子查询
- uncacheable query:不可用缓存子查询
- union: select 放在 union后面: select * from table union select * from table2
Type: 表明了查询类型,syetem > const > eq_ref > ref > range > index > ALL
-
system:表里只有一行记录
-
eq_ref:唯一性索引扫描,对于每个索引键,只有一条数据与之匹配
-
ref:非唯一性索引扫描,返回匹配的多行值
-
range:给定范围查找
-
index:Full index Scan;(全索引扫描,通常比数据文件小,比全表扫描 IO 少)sql使用了索引,但是没有通过索引进行过滤,一般使用了覆盖索引或者利用索引进行排序分组
-
all:全表扫描
mysql> explain select * from Scores where name = 'Bob';
+----+-------------+--------+------+---------------+----------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+----------+---------+-------+------+-----------------------+
| 1 | SIMPLE | Scores | ref | idx_Name | idx_Name | 258 | const | 3 | Using index condition |
+----+-------------+--------+------+---------------+----------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)
key:表明实际使用的索引,如果null表示没用,查询中若使用了覆盖索引,则该索引和查询的select字段重叠。多个索引竞争的情况下,最后用到的索引。若使用了覆盖索引,仅会在 key 中存在,不在 possible_keys中。覆盖索引:select 查询的字段刚好和建立索引的字段一一吻合 (select col1, col2, col3 from table),也就是说MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取文件,换句话说,查询列被所建的索引覆盖。
possible_keys:可能这张表用到的索引,可能不一定被实际使用到。
key_len:用于表示本次查询中,所选择的索引长度有多少字节,通常我们可借此判断联合索引有多少列被选择了。字符 * 字符集系数。数值越大越精确,where后面的判断更多。
ref:显示索引的哪一列被使用了,(where d.id = b.id),会用到 d.id 和 b.id
rows:是物理扫描行数,越少越好
Extra:Using filesort:没用到索引,使用外部的索引排序,而不是按照表内的索引顺序读取,但凡出现它查询效果很慢。要你命3k。
Extra:Using temporary:使用临时表来排序,group by没有用到索引(group by最好使用索引)。临时表很费性能。要你命3w。
Extra:Using index:使用了覆盖索引在select语句中,效率不错。如果同时出现 using where,表明索引被用来执行索引键值的查找。如果没有出现 using where,表明直接用索引读取数据而非执行查找动作。
Extra:Using join buffer:使用了连接缓存,关联字段如果没建立索引,会导致速度很慢。
Extra:Using where:全表扫描后进行了过滤。
Extra:impossible where:可能写错了sql语句。
Extra:select tables optimized away:在没有group by字句的情况下,基于索引min/max函数,查询执行计划生成的阶段即完成优化。
插入100w行数据
不建议看,只是个思路罢了。
使用SQL编程
手写,mysql为了主从复制可靠,不允许用户手写函数
mysql> show variables like 'log_bin_trust_function_creators';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF |
+---------------------------------+-------+
1 row in set (0.00 sec)
需要把它开启,然后写sql批量插入。
修改结束符号 为 $$。关闭自动提交。
单表索引优化
索引失效
- 全值匹配。查询列全在索引上且顺序一样。复合索引,如果第一个索引没被使用,后面两个索引就失效了。
- 最佳左前缀法则,从左到右的索引都被用到且没被略过,没被跳过。(带头大哥不能死,中间兄弟不能断)
- 不要再索引上做任何操作(计算,函数,类型转换),会导致索引失效转向全表扫描。例如:
- 存储引擎不能使用索引中范围条件右边的列。(中间兄弟如果用到了范围,而不是 = ,会导致后一个索引失效)
- 尽量使用覆盖索引,少用 *
- mysql使用不等于的时候(!= 或者 <>)的时候无法使用索引会导致全表扫描。
- is null, is not null:不知道哪里是空或者非空,导致全表扫描。
- like ‘%July%’ 以通配符开头,mysql索引会失效,造成全表扫描。可以通配符加在右边,例如: ‘July%’。如何解决 like 以通配符开头失效的问题?“使用覆盖索引来解决!”
- 少用 or 也会导致索引失效。
- 字符串不加单引号导致索引失效,这里其实对应的是在索引列上类型转换,数字转varchar,导致索引失效。
order by
如果复合索引是c1,c2,c3建立,那么如果order by c3, c2会导致索引失效,引起 filesort。
举个例子:
select * from table where c1='a' and c2='b' order by c3, c2;
select * from table where c1='a' order by c3, c2;
这种情况下由于第一句用到了 c2 索引,所以索引不会失效;但是下一句没用到 c2 索引,直接用了 c3 索引,导致索引失效。
排序顺序和索引顺序一致才能保证索引不失效。order by 默认升序,升序降序的时候,是会导致filesort的。
优化:
- 少用 select * 和 order by使用
group by
group by 基本都需要 order by,所以会出现order by的现象
select * from xxx where a = 3 and b like 'k%kk%' and c = 4;
上述语句用到了三个索引,abc都用到了索引
SQL优化
mysql开启满日志查询,比如超过5秒钟就是慢SQL。
- explain 观察
- show profile 观察
“小表驱动大表”,小的数据集驱动大的数据集。
select * from A where id in (select id from B);
默认 AB都建立索引
当B表的数据集必须小于A表的数据集时,使用 in 优于 exists。
当A表的数据集小于B表的数据集时,用 exists 优于 in。
MySQL锁
- 读锁:共享锁
- 写锁:排它锁
show open tables;
lock table tb1 read;
unlock tables;
加了读锁了,本session不能读取其他没加锁的表。
- 表锁:偏读
- 行锁:偏写
加了写锁,本session不能写其他没加锁的表,其他session读取只能阻塞
无索引行锁升级为表锁!!! varchar类型不加"",会导致索引失效,自动类型转化,导致升级成表锁。
间隙锁危害
当用范围条件修改数据的时候,mysql会给出间隙锁(GAP),锁定给定范围内的所有键值,导致无法插入不存在但是属于这个范围内的数据。导致性能变慢。
如何锁定一行
select * from table1 where a = 'a' for update;
这里人为锁定当前行。其他session只能读取没法操作数据。
mysql> show status like 'innodb_row_lock%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0 | //正在等待锁定的数量
| Innodb_row_lock_time | 0 |
| Innodb_row_lock_time_avg | 0 | //等待平均时间
| Innodb_row_lock_time_max | 0 | //等待最大时间
| Innodb_row_lock_waits | 0 | //等待总次数
+-------------------------------+-------+
5 rows in set (0.00 sec)
主从复制
原理:
slave 会从 master 读取 binlog 来进行数据同步
- master把数据改变写入 binlog 中,成为 binary log event
- slave IO 线程读 master Binary log,并拷贝到它的中继日志(relay log)
- slave 重做 中继日志的事件,改变自己的数据库,MySQL复制是异步的且串行化
每个slave 只有一个master,每个slave只有一个服务 ID,一个master有多个slave。
配置主机参数,允许从机拉去数据,从机做相应配置。通过show master status获取文件和偏移量来获取数据。必须保证下面两个参数Yes,才保证主从设置成功:
- Slave_IO_Running: Yes
- Slave_SQL_Running: Yes
本文地址:https://blog.csdn.net/weixin_40037938/article/details/112599246
下一篇: linux下free命令详解