mysql基础知识(高性能mysql第三版)

  • Mysql文件物理组成
  • mysql表结构设计
  • 基础的sql语句以及函数
  • 安全性
  • mac下的常用操作

前言:

mysql逻辑架构:
在这里插入图片描述

mysql的逻辑架构大概分为三层:

第一层: 服务层(为客户端服务)
为请求做连接处理,授权认证,安全等。

第二层:核心服务
比如查询解析,优化,缓存,内置函数。存储过程,触发器,视图等。对于第二层来说,所以跨存储引擎的功能都在这一层实现。

第三层:存储引擎
负责mysql中数据的存储和提取。服务器通过api与存储引擎通信,这些接口屏蔽了存储引擎之间的差异。也就是说,接口的存在,导致不同存储引擎的差异不会影响到上层查询过程。
架构分层之后,可以更好的理解一些问题,比如我们很关心的并发问题:mysql层面的并发控制,实际上是分为两种:

服务层的并发
存储引擎层的并发的

mysql的系统架构:
在这里插入图片描述
在这里插入图片描述

锁是完全在存储引擎层实现的,所以不同的存储引擎会有不同的锁策略和锁粒度。什么是锁粒度呢?可以简单的理解为,需要锁定的部分的范围。

常见的锁策略有表锁和行锁。这是按照锁粒度去区分的。
显然表锁的粒度更大,并发性能较差,不过CPU的开销小。(上锁也是需要开销的)
而行锁的粒度更小,并发性能较好,但是CPU的开销更大。

假设一种极端的情况,我们需要系统具有最大的并发性。那么,我们在锁策略的选择上就应该选取粒度最小的那种。理想情况就是:
尽量只锁定需要修改的那部分数据。
锁另一种区分方式是:读锁和写锁。

读锁又叫共享锁,比如你的网站的多个用户,是可以同时读取同一个资源的。
写锁又叫排他锁,写锁的特征就是阻塞。当一个用户在修改某条数据时,其他用户是无法获取到读锁或写锁的。

当然服务层的某些行为也会给表上锁,比如当执行alter table时,服务器会给该表上表锁。

事务
事务即一组原子性的sql查询。
常规的概念就不说了,这里只提醒三点:

事务也是在存储引擎层实现的
事务会带来开销
一条sql语句也是一个事务(这里对讲解MVCC会有帮助)

mysql隔离级别
在这里插入图片描述
1.Read Uncommited (未提交读)
事务可以读取未提交的数据,也称脏读。非常可怕,基本不会使用这一级别。

2.Read Commited (提交读)
一个事务从开始到提交之前,所做的修改对其他事务是不可见的。但是重复执行同样的查询可能会导致不同的结果。

3.Repeatable Read (可重复读)
这是mysql的默认隔离级别,重复执行同样的查询结果相同。

4.Serializable (可串行化)
最高的隔离级别,它强制事务串行执行。会导致大量的超时和锁争用问题。虽然数据一致性好,但是并发能力很弱,一般也很少使用。
隔离级别先讲到这里,想讲清楚隔离级别是需要先了解lnnodb的。隔离级别的实现,锁机制的实现,以及事务的实现都是依托于一个核心存储引擎。而无数人的经验告诉我们,innodb在绝大多数情况下都会是最佳的选择。

InnoDB存储引擎

InnoDB:用于MySQL的事务安全(ACID支持)存储引擎,具有提交,回滚和崩溃恢复的功能以保护用户数据。 InnoDB行级锁定(不升级到更粗的粒度锁)和Oracle风格的非锁定读取增加了多用户并发性和性能。 InnoDB将用户数据存储在聚簇索引中,以减少基于主键的常见查询的I / O。 为了保持数据完整性,InnoDB还支持FOREIGN KEY参照完整性约束。 InnoDB是MySQL 5.6中的默认存储引擎。

从这段中,我们能了解的信息很多。支持事务,能崩溃恢复,行级锁,非锁定读,聚簇索引,外键等等

通过MVCC,实现nonlocking reads(快照读)
repeatable是mysql默认的隔离级别。它实现了非锁定读nonlocking reads,也可以叫做快照读。

原理解析:
现在,我们假设一种情况。有一个事务A由n条sql组成,第一条sql是查询id为10的数据,中间有很多不相干的sql,到第n条sql又是查询这条id为10的数据。

既然不上读锁。意味着在你的这个事务执行时,另一个事务B是可以修改id为10的这条记录的。那么是怎么保证Repeatable Read (可重复读),重复执行同样的查询结果相同。修改之后结果应该不同才对。
在这里插入图片描述
MVCC的实现是通过保存数据在某个时间点的快照实现的。正是它的存在,导致nonlocking reads成为可能。
在这里插入图片描述

MVCC—秒懂百科下

Multi-Version Concurrency Control 多版本并发控制,MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问;在编程语言中实现事务内存。

Mysql文件物理组成

在这里插入图片描述

以下的所有[=file_name],都表示日志存放的绝对路径。

错误日志 Error Log
记录了mysql Server 运行中所有警告和错误信息,以及mysql server 每次启动和关闭的详细信息。
通过–log-error[=file_name] 开启。log默认存放在数据目录下,以hostname.err命名。

二进制日志 binlog
通过 --log-bin[=filename]开启,mysql会将修改数据库数据的query以二进制的形式记录到日志里。还包含每条query的执行时间,所消耗的资源,和事务信息,所以binlog是事务安全的。
–max_binlog_size 设置binlog的最大存储上限
–binlog-do-db=dbname 只针对该db记录binlog
–binlog-ignore-db=dbname 不记录某个db的binlog

mysql-bin.index 记录所有的bin log的绝对路径,mysql各种线程会根据它来找到bin log

查询日志 query log
通过 --log[=filename]开启,由于记录了所有的query,体积大,开启后对性能有较大影响,慎用。

慢查询日志 slow query log
通过 --log-slow-queries[=filename]开启,记录执行时间较长的query。
mysqlslowdump: 分析慢查询日志的工具程序

innodb 的redo log和undo log
用于保障事务安全性。

数据文件

.frm 文件
无论什么存储引擎:每个表都有一个以表名命名的 frm文件,存放表的元数据(meta)信息,包括表结构的定义信息等。

.ibd 文件 和 ibdata 文件 (innodb专属)
通过独享表空间形式:
通过innodb_file_per_table=ON 来开启
使用ibd文件来存放数据,且每个表一个ibd文件。

共享形式:
使用ibdata文件,所有表共同使用一个(或者多个、自行配置)ibdata文件。
innodb_data_home_dir ibdata文件目录
innodb_data_file_path 每一个ibdata文件的名称,可以配置多个。
目录为空的话,file_path就需要填写绝对路径了。
可以指定ibdata文件的大小,只有最后一个ibdata文件可以配置成自动扩展类型。

replication 相关文件

master.info文件
存放该slave的Master端信息,master的主机地址、连接信息、日志位置

relay log 和 relay log index
mysql-relay-bin:存放slave端的IO进程从master端所读取的binlog信息。
然后slave的sql解析线程,从relaylog中读取并解析相应的日志信息,转化成master所执行的sql,接着在slave端应用。

mysql-relay-bin-index 类似 mysql-bin-index。记录relay log存放的绝对路径

relay-log.info文件
记录relay-log的相关信息,方便线程随时获取。

其他文件

system config file 系统配置文件my.conf,位于/etc下。
pid 文件,是mysqld应用在Unix环境下的一个进程文件,存放着自己的进程id
socket 文件,用户在Unix环境下的客户端连接可以不通过tcp/ip,而直接使用Unix Socket来连接mysql

MySQL表结构设计

DDL语句设计
在这里插入图片描述
https://www.jianshu.com/p/dc58a4efdd84
整数类型
(可以使用无符号整数类型,提高存储范围)(类似int(2)不会减少其真正存储空间,1只是表示显示的长度为1位),如下:
在这里插入图片描述
字符类型
在这里插入图片描述

char(32)括号里表示的是字符数,32指示要存储的最大字符数。
一个汉字,一个数字,一个中文,都是一个字符。但是对于不同的编码方式而言,存储每个字符所需要的字节数是不一样的。

实数类型
在这里插入图片描述
日期类型

在这里插入图片描述
2038挺别致的原因
数据库命名规范

数据库名使用小写英文以及下划线组成.比如: my_db
备份数据库名使用正式库名加上备份时间组成,如: dbname_20070403
不得超过 30 个字符

数据库表命名规范

数据表名使用小写英文以及下划线组成
备份数据表名使用正式表名加上备份时间组成,如:
不得超过 30 个字符
info_user_20070403
system_destination_20070403

字段设计规范

在一个系统中,保持字段名和类型的一致性。表与表之间的相关联字段要用统一名称。
字段名不宜过长
用尽量少的存储空间来存数一个字段的数据。能用 char(20)的就不用 varchar(255),能用tinyint的就不用int。
尽量避免空(NULL),要尽可地把字段定义为NOT NULL。因为MySQL难以优化了使用了可空列的查询,它会使索引、索引统计和值更加复杂。可空列需要更多的存储空间,还需要在MySQL内部进行特殊处理。

其他设计技巧

避免使用触发器。触发器的功能通常可以用其他方式实现.在调试程序时触发器可能成为干扰. 假如你确实需要采用触发器,你最好集中对它文档化.
避免使用存储过程
使用常用英语(或者其他任何语言)而不要使用拼音首字母缩写

数据库设计之范式与冗余设计
先提一点,三范式可以很好的保证表结构的原子性,但是实际应用的时候,也常常使用逆范式的设计。因为面对大量数据时,连表是致命的。

第一范式(1NF)
概念
数据表的每个字段(属性)必须是唯一的、不可分割的。
唯一性
比如:在一张学生信息表里不能有两个名称都是name的字段。
不可分割性
比如:在一张学生信息表不能出现类似name_mobile这样的字段,很明显name_mobile是可以分割成name和mobile两个字段的。

第二范式(2NF)
概念
数据表的每条记录必须是唯一的(主键约束),且非主键字段只依赖于主键。
唯一性
比如说:不能同时存在id = 1的记录(id为主键)。
依赖性
比如说:在一张学生信息表(student_id为主键),不应该出现course_name(课程名称,依赖于course_id)这样的字段,因为,如果有一天,《心理健康教育》课程名要改成《心理健康教育杂谈》,就得改课程表和学生信息表的课程名称了。

第三范式(3NF)
概念
数据表中不应该存在多余的字段,也就是说每个字段都不能由其他字段推理得到。
例子
比如说:学生信息表里不能同时存在province_id(省份ID)、city_id(城市ID)这两个字段,因为province_id可以由city_id推理得到

逆范式
概念
就是不按照标准的范式去设计数据库

在数据库的实践过程中,我们可能遇到数据量非常大的数据表,这时候去做join查询是非常损耗性能的,甚至导致数据库连接超时、挂掉等问题。所以呢,有时候就需要数据库多冗余设计,对一些字段做冗余,以避免大表之间的join。

基础SQL:

http://www.w3school.com.cn/sql/sql_autoincrement.asp

MySQL安全性:

在这里插入图片描述

第一层防线:网络
尽可能地让Mysql处于一个有保护的局域网之中
实在有需要从公网连接的话,再通过跳板机做端口转发
处在局域网之内的mysql,由于有局域网出入口设备的保护,相对于暴露在广域网中要安全不少。主要威胁对象基本控制为可以接入局域网的内部潜在威胁者 和 极少数可以突破局域网出入口安全设备的入侵者。
所以,这是非常必要的。

第二层防线:主机
系统账号都改成基于ssh key认证,不允许远程密码登入,且ssh key的算法、长度有要求以确保相对安全。
禁止root账号远程登录主机
正确设置MySQL及其他数据库服务相关目录权限,不要全是755,一般750就够了
一个恶意入侵者登录上主机的话,可以通过各种方式登录自身安全设置不完善的数据库。也可以通过盗取或删除数据文件的方式发起破坏。

第三道防线:数据库
要严格限制数据库账号权限级别。业务帐号,权限最小化,坚决不允许DROP、TRUNCATE权限
设置MySQL账号的密码安全策略,包括长度、复杂性。
通过基本的用户管理模块,负责用户登录连接相关的基本权限控制,登入密码。
通过访问授权控制模块,校验用户是否拥有所请求数据的访问权限

应用层面:
启用 safe-update 选项,避免没有 WHERE 条件的全表数据被修改;
在应用中尽量不直接DELETE删除数据,而是设置一个标志位就好了。需要真正删除时,交由DBA先备份后再物理删除,避免误操作删除全部数据。
sql注入问题
在web server层,可以用一些安全模块,比如nginx的WAF模块;

sql注入到底是什么?

sql注入,简单地说就是执行恶意的sql语句,或者说是构造恶意的sql语句。

如何进行sql注入
进行sql注入的方式可谓是千奇百怪了,虽然这也从侧面证明了sql的功能是多么的强大。
常见的恶意sql都是怎么构造的。

1、OR 1 =1

2、利用注释符
mysql中有两种注释符 # 和 –
SELECT * FROM user WHERE username = ‘user’#'AND password = ‘111’
SELECT * FROM user WHERE username = ‘user’-- 'AND password = ‘111’
这样一注释,后面的语句就失效了。相当于执行了:
SELECT * FROM user WHERE username = ‘user’
达到巧妙避开密码验证的效果

3、利用union
union会把结果拼拼到一起,所有要让union前面的查询返回一个空值,一般采用类似于id=-1的方式。
UNION 需要两个被select的集合拥有相同的列数。
// 获取数据库名列表
select name from students where id = -1 union select schema_name from information_schema.schemata;

如何防范sql注入?
不要信任用户的输入,对用户的输入进行校验。如用mysqli_real_escape_string()函数
开发时尽量用安全函数代替不安全函数,编写安全代码。危险函数,常见的执行命令函数,动态访问函数,如C语言中的system(),PHP的eval(),JSP的include()导致的代码越权执行,都是注入。

不要使用动态拼装sql,使用参数化的sql。预编译语句,绑定变量。使用预编译的SQL语句,SQL的语意不会变化,攻击者无法改变SQL的结构
限制mysql客户端用户的权限
不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。
应用的异常信息,对外应该给出尽可能少的提示。

检测现有系统是否有sql注入的风险?

使用SQL注入工具- sqlmap – 开源跨平台, 很多公司都在使用sqlmap作为安全扫描服务的底层依赖。

判断是否有SQL漏洞
python sqlmap.py -u “http://www.site.com/login.php?id=3
以“5”级别检测
python sqlmap.py -u “http://www.site.com/login.php?id=3” --dbs --level 5

mysql权限系统介绍

在这里插入图片描述
在这里插入图片描述

权限系统实现原理

mysql的权限信息存储在如下几个被称为grant tables的系统表中。
mysql.User
mysql.db
mysql.table_priv
mysql.column_priv
mysql.Host (已废弃)

这些信息会被频繁访问,所以会加载到内存里。如果手动修改了上述的表,就需要调用FLUSH PRIVILEGES来重新加载内存。
通过GRANT,REVOKE, CREATE USER, DROP USER来修改权限的话,就会自动更新内存里的权限信息,无需调用FLUSH PRIVILEGES

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
查询权限的时候,也是从global -> db -> table …level从大到小的顺序查询的。
也就是说,如果mysql.User表中有匹配到row,就会使用该行数据进行权限判断,不会再继续往后查找是否还有匹配的信息了。
如果查询到多行,则会使用host信息最接近的,其余的都不会使用。

授予或者取消用户的权限

global level权限
其作用域是所有数据库中的所有对象。要授予global level权限,只需在执行GRANT命令时,用“.”指定适用范围是Global即可
GRANT SELECT,UPDATE,DELETE,INSERT ON . TO ‘username’@‘localhost’
@后面的是用户的来访主机

database level
其作用域是整个数据库中所有的对象。database level相对于global level少了以下几个权限。CREATE USER、FILE、PROCESS、RELOAD、REPLICATION CLIENT、REPLICATION SLAVE、SHOW DATABASES、SHUTDOWN、SUPER和USAGE。
要授予database level权限,只需通过"database."即可
GRANT ALTER ON test.
TO ‘username’@‘localhost’;
获取用户在某个来访主机下的访问权限:
SHOW GRANTS FOR username@localhost
也可以先通过USE一个数据库,把作用域限定在该数据库下,然后直接""即可。
USE test;
GRANT ALTER ON * TO ‘username’@‘localhost’;
给多个用户授权,用,分隔即可。
grant create on perf.
to ‘abc’@‘localhost’,‘def’@‘localhost’;

username@host表示授予的用户以及允许该用户登录的IP地址。
其中Host有以下几种类型:
localhost:只允许该用户在本地登录,不能远程登录。
%:允许在除本机之外的任何一台机器远程登录。
192.168.52.32:具体的IP表示只允许该用户从特定IP登录。
在这里插入图片描述
在这里插入图片描述

查看用户权限
查看当前用户自己的权限:
show grants;
查看其他 MySQL 用户权限:
show grants for dba@localhost;

撤销用户权限

使用revoke 命令来注销用户的权限,具体语法:
要撤销所有权限,需使用以下语法。此语法用于取消对于已命名的用户的所有全局层级、数据库层级、表层级和列层级的权限。
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] …
指定具体的权限:
REVOKE SELECT FROM username@localhost
注意:
1 使用GRANT或REVOKE,操作者必须拥有GRANT OPTION权限.
2 使用REVOKE撤销全部权限, 操作者必须拥有mysql数据库的全局CREATE USER权限或UPDATE权限。

mysql 授权策略

了解来访主机
了解用户需求,为工作分类。尽可能少地给用户权限
确保GRANT OPTION权限只有超级用户才有
使用私有局域网络
使用ssl加密通道
访问授权限定来访主机信息


配置文件

MySQL启动时会读取配置文件my.cnf,读取次序依次为 /etc/my.cnf、/etc/mysql/my.cnf、/usr/local/etc/my.cnf、~/.my.cnf。
安装完MySQL后,可能上述位置上都没有my.cnf文件,要想指定配置文件,可以将MySQL安装目录下的示例配置文件拷贝到对应位置。
$ cp $(brew --prefix mysql)/support-files/my-default.cnf /etc/my.cnf

猜你喜欢

转载自blog.csdn.net/wolf_love666/article/details/87948930