1、简介
MySQL的历史可以追溯到1979年,一个名为Monty Widenius的程序员在为TcX的小公司打工,并且用BASIC设计了一个报表工具,使其可以在4MHz主频和16KB内存的计算机上运行。当时,这只是一个很底层的且仅面向报表的存储引擎,名叫Unireg。【MySQL早期叫Unireg】早期轻量级,后来发展到巨无霸(淘宝、faceboock)MySQL AB是由MySQL创始人和主要开发人创办的公司。MySQL AB最初是由David Axmark、Allan Larsson和Michael“Monty”Widenius在瑞典创办的。
mysql 详解
SQL标准:ANSI SQL
SQL-86, SQL-89, SQL-92, SQL-99, SQL-03
SQL四种语言:DDL,DML,DCL,TCL
DDL(Data Definition Language)数据定义语言
DML(Data Manipulation Language)数据操纵语言
DCL(Data Control Language)数据库控制语言 授权,角色控制等
TCL(Transaction Control Language)事务控制语言
SAVEPOINT 设置保存点
ROLLBACK 回滚
SET TRANSACTION
SQL主要分成四部分:
(1)数据定义。(SQL DDL)用于定义SQL模式、基本表、视图和索引的创建和撤消操作。
(2)数据操纵。(SQL DML)数据操纵分成数据查询和数据更新两类。数据更新又分成插入、删除、和修改三种操作。
(3)数据控制。包括对基本表和视图的授权,完整性规则的描述,事务控制等内容。
(4)嵌入式SQL的使用规定。涉及到SQL语句嵌入在宿主语言程序中使用的规则。
mysql 详解
启动3306端口 (连接池认证成功进入,不成功退出;(Check Memory -Caches)查询缓存,直接查找该sql语句的执行结果,如果命中直接返回,否则继续生成查询计划、解析sql语句;经优化,查找buffers cache里面的语句,尝试加载buffers cache语句,如果buffers cache里没有语句,则通过特定引擎与io设备进行交互。)
查询的执行路径:
mysql 详解
日常的学习和工作中我确认深深感受到数据结构和算法的重要性,很多东西,如果你愿意稍稍往深处挖一点,那么扑面而来的一定是各种数据结构和算法知识。
经典的BTREE索引数据结构如下图:
mysql 详解
B-Tree 索引是 MySQL 数据库中使用最为频繁的索引类型,除了 Archive 存储引擎之外的其他所有的存储引擎都支持 B-Tree 索引。不仅仅在 MySQL 中是如此,实际上在其他的很多数据库管理系统中B-Tree 索引也同样是作为最主要的索引类型,这主要是因为B-Tree 索引的存储结构在数据库的数据检索中有非常优异的表现。
一般来说, MySQL 中的 B-Tree 索引的物理文件大多都是以 Balance Tree 的结构来存储的,也就是所有实际需要的数据都存放于 Tree 的 Leaf Node ,而且到任何一个 Leaf Node 的最短路径的长度都是完全相同的,所以我们大家都称之为 B-Tree 索引当然,可能各种数据库(或 MySQL 的各种存储引擎)在存放自己的 B-Tree 索引的时候会对存储结构稍作改造。如 Innodb 存储引擎的 B-Tree 索引实际使用的存储结构实际上是 B+Tree ,也就是在 B-Tree 数据结构的基础上做了很小的改造,在每一个Leaf Node 上面出了存放索引键的相关信息之外,还存储了指向与该 Leaf Node 相邻的后一个 LeafNode 的指针信息,这主要是为了加快检索多个相邻 Leaf Node 的效率考虑。
B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接。
在B+树上的常规检索,从根节点到叶子节点的搜索效率基本相当,不会出现大幅波动,而且基于索引的顺序扫描时,也可以利用双向指针快速左右移动,效率非常高。
mysql 详解
因此,B+树索引被广泛应用于数据库、文件系统等场景。顺便说一下,xfs文件系统比ext3/ext4效率高很多的原因之一就是,它的文件及目录索引结构全部采用B+树索引,而ext3/ext4的文件目录结构则采用Linked list, hashed B-tree、Extents/Bitmap等索引数据结构,因此在高I/O压力下,其IOPS能力不如xfs。
Lex & Yacc 是用来生成词法分析器和语法分析器的工具,它们的出现简化了编译器的编写。Lex & Yacc 分别是由贝尔实验室的 Mike Lesk 和 Stephen C. Johnson 在 1975 年发布。
mysql 详解
MySQL事务:
事务:一组原子性的SQL查询,或者说一个独立工作单元。
事务日志:
ACID测试:
A:atomicity,原子性;整个事务中的所有操作要么全部成功执行,要么全部失败后回滚;
C:consistency, 一致性;数据库总是从一个一致性状态转换为另一个一致性状态;
I:Isolation,隔离性;一个事务所做出的操作在提交之前,是不能为其它所见;隔离有多种隔离级别;
D:durability: 持久性;一旦事务提交,其所做的修改会永久保存于数据库中;
事务:
启动事务:START TRANSACTION
结束事务:
(1) COMMIT:提交
(2) ROLLBACK: 回滚
注意:只有事务型存储引擎方能支持此类操作;
建议:显式请求和提交事务,而不要使用“自动提交”功能;
autocommit={1|0}
事务支持savepoint
SAVEPOINT identifier
ROLLBACK [WORK] TO [SAVEPOINT] identifier
RELEASE SAVEPOINT identifier
事务隔离级别:
READ UNCOMMITTED (读未提交)【脏读、不可重复读、幻读】
READ COMMITTED (读提交)【不可重复读、幻读】
REPEATABLE READ (可重读)【幻读】【默认[InnoDB]MySQL存储引擎使用的隔离级别"可重读"】
SERIALIZABLE (可串行化)【加锁读】
可能存在问题:
脏读;
不可重复读;
幻读;
加锁读;
MySQL用户和权限管理:
权限类别:
库级别
表级别
字段级别
管理类
程序类
管理类:
CREATE TEMPORARY TABLES
CREATE USER
FILE
SUPER
SHOW DATABASES
RELOAD
SHUTDOWN
REPLICATION SLAVE
REPLICATION CLIENT
LOCK TABLES
PROCESS
程序类:
FUNCTION
PROCEDURE
TRIGGER
CREATE, ALTER, DROP, EXCUTE
库和表级别:TABLE or DATABASE
ALTER
CREATE
CREATE VIEW
DROP
INDEX
SHOW VIEW
GRANT OPTION:能够把自己获得的权限赠经其他用户一个副本;
数据操作:
SELECT
INSERT
DELETE
UPDATE
字段级别:
SELECT(col1,col2,...)
UPDATE(col1,col2,...)
INSERT(col1,col2,...)
所有有限:ALL PRIVILEGES, ALL
元数据数据库:mysql
授权表:
db, host, user
columns_priv, tables_priv, procs_priv, proxies_priv
用户账号:br/>'USERNAME'@'HOST':
@'HOST':
主机名;
IP地址或Network;
通配符:
%, _: 172.16.%.%
创建用户:CREATE USER
CREATE USER 'USERNAME'@'HOST' [IDENTIFIED BY 'password'];
查看用户获得的授权:SHOW GRANTS FOR
SHOW GRANTS FOR 'USERNAME'@'HOST'
用户重命名:RENAME USER
RENAME USER old_user_name TO new_user_name
删除用户:DROP USER 'USERNAME'@'HOST'
修改密码:
(1) SET PASSWORD FOR
(2) UPDATE mysql.user SET password=PASSWORD('your_password') WHERE clause;
(3) mysqladmin password
mysqladmin [OPTIONS] command command....
-u, -h, -p
忘记管理员密码的解决办法:
(1) 启动mysqld进程时,为其使用:--skip-grant-tables --skip-networking
(2) 使用UPDATE命令修改管理员密码
(3) 关闭mysqld进程,移除上述两个选项,重启mysqld;
授权:GRANT
GRANT priv_type[,...] ON [{table|function|procedure}] db.{table|routine} TO 'USERNAME'@'HOST' [IDENTIFIED BY 'password']
[REQUIRE SSL] [WITH with_option]
with_option:
GRANT OPTION
| MAX_QUERIES_PER_HOUR count
| MAX_UPDATES_PER_HOUR count
| MAX_CONNECTIONS_PER_HOUR count
| MAX_USER_CONNECTIONS count
取消授权:REVOKE
REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] priv_level FROM user [, user] ...
2、各存储引擎的特性
InnoDB:
事务:事务日志
外键:
MVCC:
聚簇索引:
聚簇索引之外的其它索引,通常称为辅助索引
行级锁:间隙锁
支持辅助索引
支持自适应hash索引
支持热备份
MyISAM:
全文索引
压缩:用于实现数据仓库,能节约存储空间并提升性能
空间索引
表级锁
延迟更新索引
不支持事务、外键和行级锁
崩溃后无法安全恢复数据
适用场景:只读数据、较小的表、能够容忍崩溃后的修改操作和数据丢失
ARCHIVE:
仅支持INSERT和SELECT,支持很好压缩功能;
适用于存储日志信息,或其它按时间序列实现的数据采集类的应用;
不支持事务,不能很好的支持索引;
CSV:
将数据存储为CSV格式;不支持索引;仅适用于数据交换场景;
BLACKHOLE:
没有存储机制,任何发往此引擎的数据都会丢弃;其会记录二进制日志,因此,常用于多级复制架构中作中转服务器;
MEMORY:
保存数据在内存中,内存表;常用于保存中间数据,如周期性的聚合数据等;也用于实现临时表
支持hash索引,使用表级锁,不支持BLOB和TEXT数据类型
MRG_MYISAM:是MYISAM的一个变种,能够将多个MyISAM表合并成一个虚表;
NDB:是MySQL CLUSTER中专用的存储引擎
第三方的存储引擎:
OLTP类:
XtraDB: 增强的InnoDB,由Percona提供;
编译安装时,下载XtraDB的源码替换MySQL存储引擎中的InnoDB的源码
PBXT: MariaDB自带此存储引擎
支持引擎级别的复制、外键约束,对SSD磁盘提供适当支持;
支持事务、MVCC
TokuDB: 使用Fractal Trees索引,适用存储大数据,拥有很好的压缩比;已经被引入MariaDB;
列式存储引擎:
Infobright: 目前较有名的列式引擎,适用于海量数据存储场景,如PB级别,专为数据分析和数据仓库设计;
InfiniDB
MonetDB
LucidDB
开源社区存储引擎:
Aria:前身为Maria,可理解为增强版的MyISAM(支持崩溃后安全恢复,支持数据缓存)
Groona:全文索引引擎,Mroonga是基于Groona的二次开发版
OQGraph: 由Open Query研发,支持图结构的存储引擎
SphinxSE: 为Sphinx全文搜索服务器提供了SQL接口
Spider: 能数据切分成不同分片,比较高效透明地实现了分片(shared),并支持在分片上支持并行查询;
3、MySQL 数据类型
MySQL中定义数据字段的类型对你数据库的优化是非常重要的。MySQL支持多种类型,大致可以分为字符型、数值型、日期时间型、内建类型。通常也可分为三类:数值、日期/时间和字符串(字符)类型。
字符型:
CHAR, BINARY:定长数据类型;【CHAR不区分字符大小写,BINARY区分字符大小写】
VARCHAR, VARBINARY:变长数据类型;需要结束符;
TEXT:TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT
BLOB: TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
ENUM, SET
ENUM 类型因为只允许在集合中取得一个值,有点类似于单选项。SET 类型与 ENUM 类型相似但不相同。SET 类型可以从预定义的集合中取得任意数量的值。
mysql 详解
数值型:
精确数值型:
整型:TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT
十进制型:DECIMAL 【在金融领域中通常用的是十近制】
近似数值型
浮点型:
FLOAT
DOUBLE
BIT 【一般不建议使用】
mysql 详解
日期时间型:
DATE
TIME
DATETIME
TIMESTAMP
YEAR(2), YEAR(4)
mysql 详解
字符类型修饰符:
NOT NULL: 非空约束;
NULL:
DEFAULT 'STRING': 指明默认值;
CHARACTER SET '':使用的字符集;
COLLATION:使用的排序规则
整型数据修饰型:
NOT NULL
NULL
DEFAULT NUMBER
AUTO_INCREMENT:
UNSIGNED
PRIMARY KEY|UNIQUE KEY
NOT NULL
mysql> SELECT LAST_INSERT_ID();
日期时间型修饰符:
NOT NULL
NULL
DEFAULT
内建类型SET和ENUM的修饰符:
NOT NULL
NULL
DEFAULT
4、SQL MODE
常用SQL MODE有:TRADITIONAL, STRICT_TRANS_TABLES, or STRICT_ALL_TABLES。SQL_MODE可能是比较容易让开发人员和DBA忽略的一个变量,默认为空。SQL_MODE的设置是比较有风险的一种设置,因为在这种设置下可以允许一些非法操作,比如可以将NULL插入NOT NULL的字段中,也可以插入一些非法日期,如“2019-12-33”。因此在生产环境中强烈建议开发人员将这个值设为严格模式,这样有些问题可以在数据库的设计和开发阶段就能发现,而如果在生产环境下运行数据库后发现这类问题,那么修改的代价将变得十分巨大。
mysql 详解
mysql 详解
sql_mode常用值如下:
ONLY_FULL_GROUP_BY:
对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么这个SQL是不合法的,因为列不在GROUP BY从句中
NO_AUTO_VALUE_ON_ZERO:
该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。如果用户 希望插入的值为0,而该列又是自增长的,那么这个选项就有用了。
STRICT_TRANS_TABLES:
在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制
NO_ZERO_IN_DATE:
在严格模式下,不允许日期和月份为零
NO_ZERO_DATE:
设置该值,mysql数据库不允许插入零日期,插入零日期会抛出错误而不是警告。
ERROR_FOR_DIVISION_BY_ZERO:
在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如 果未给出该模式,那么数据被零除时MySQL返回NULL
NO_AUTO_CREATE_USER:
禁止GRANT创建密码为空的用户
NO_ENGINE_SUBSTITUTION:
如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常
PIPES_AS_CONCAT:
将"||"视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似
ANSI_QUOTES:
启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符
ORACLE的sql_mode设置等同:PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, NO_KEY_OPTIONS, NO_TABLE_OPTIONS, NO_FIELD_OPTIONS, NO_AUTO_CREATE_USER.
5、SQL语法
创建一个数据库
使用 create database 语句可完成对数据库的创建, 创建命令的格式如下:
create database 数据库名 [其他选项];
创建数据库表
使用 create table 语句可完成对表的创建, create table 的常见形式:
create table 表名称(列声明);
表中插入数据
insert 语句可以用来将一行或多行数据插到数据库表中, 使用的一般形式如下:
insert [into] 表名 [(列名1, 列名2, 列名3, ...)] values (值1, 值2, 值3, ...);
查询表中的数据
select 语句常用来根据一定的查询规则到数据库中获取数据, 其基本的用法为:
select 列名称 from 表名称 [查询条件];
按特定条件查询:
where 关键词用于指定查询条件, 用法形式为: select 列名称 from 表名称 where 条件;
更新表中的数据
update 语句可用来修改表中的数据, 基本的使用形式为:
update 表名称 set 列名称=新值 where 更新条件;
删除表中的数据
delete 语句用于删除表中的数据, 基本用法为:
delete from 表名称 where 删除条件;
创建后表的修改
添加列
基本形式: alter table 表名 add 列名 列数据类型 [after 插入位置];
修改列
基本形式: alter table 表名 change 列名称 列新名称 新数据类型;
删除列
基本形式: alter table 表名 drop 列名称;
重命名表
基本形式: alter table 表名 rename 新表名;
删除整张表
基本形式: drop table 表名;
删除整个数据库
基本形式: drop database 数据库名;
SELECT语句的执行流程:
FROM Clause --> WHERE Clause --> GROUP BY --> HAVING Clause --> ORDER BY --> SELECT --> LIMIT
mysql 详解
单表查询:
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[SQL_CACHE | SQL_NO_CACHE]
select_expr [, select_expr ...]
[FROM table_references
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[FOR UPDATE | LOCK IN SHARE MODE]
DISTINCT: 数据去重;
SQL_CACHE: 显式指定存储查询结果于缓存之中;
SQL_NO_CACHE: 显式查询结果不予缓存;
query_cache_type的值为'ON'时,查询缓存功能打开;
SELECT的结果符合缓存条件即会缓存,否则,不予缓存;
显式指定SQL_NO_CACHE,不予缓存;
query_cache_type的值为'DEMAND'时,查询缓存功能按需进行;
显式指定SQL_CACHE的SELECT语句才会缓存;其它均不予缓存;
字段显示可以使用别名:
col1 AS alias1, col2 AS alias2, ...
WHERE子句:指明过滤条件以实现“选择”的功能:
过滤条件:布尔型表达式;
算术操作符:+, -, *, /, %
比较操作符:=, !=, <>, <=>, >, >=, <, <=
BETWEEN min_num AND max_num
IN (element1, element2, ...)
IS NULL
IS NOT NULL
LIKE:
%: 任意长度的任意字符;
_:任意单个字符;
RLIKE:
REGEXP:匹配字符串可用正则表达式书写模式;
逻辑操作符:
NOT
AND
OR
XOR
GROUP:根据指定的条件把查询结果进行“分组”以用于做“聚合”运算:
avg(), max(), min(), count(), sum()
HAVING: 对分组聚合运算后的结果指定过滤条件;
ORDER BY: 根据指定的字段对查询结果进行排序;
升序:ASC
降序:DESC
LIMIT [[offset,]row_count]:对查询的结果进行输出行数数量限制;
对查询结果中的数据请求施加“锁”:
FOR UPDATE: 写锁,排他锁;
LOCK IN SHARE MODE: 读锁,共享锁
多表查询:
交叉连接:笛卡尔乘积;
内连接:
等值连接:让表之间的字段以“等值”建立连接关系;
不等值连接
自然连接
自连接
外连接:
左外连接:
FROM tb1 LEFT JOIN tb2 ON tb1.col=tb2.col
右外连接
FROM tb1 RIGHT JOIN tb2 ON tb1.col=tb2.col
子查询:在查询语句嵌套着查询语句
基于某语句的查询结果再次进行的查询
用在WHERE子句中的子查询:
(1) 用于比较表达式中的子查询;子查询仅能返回单个值;
SELECT Name,Age FROM students WHERE Age>(SELECT avg(Age) FROM students);
(2) 用于IN中的子查询:子查询应该单键查询并返回一个或多个值从构成列表;
SELECT Name,Age FROM students WHERE Age IN (SELECT Age FROM teachers);
(3) 用于EXISTS;
用于FROM子句中的子查询;
使用格式:SELECT tb_alias.col1,... FROM (SELECT clause) AS tb_alias WHERE Clause;
示例:
SELECT s.aage,s.ClassID FROM (SELECT avg(Age) AS aage,ClassID FROM students WHERE ClassID IS NOT NULL GROUP BY ClassID) AS s WHERE s.aage>30;
联合查询:UNION
SELECT Name,Age FROM students UNION SELECT Name,Age FROM teachers;
6、MySQ设计规范
数据库设计尽量遵循第三范式(3NF)的要求。即某个表只包括其本身基本的属性,当不是它们本身所具有的属性时需进行分解。表之间的关系通过外键相连接。它具有以下特点:有一组表专门存放通过键连接起来的关联数据。
对于因效率等原因,无法遵循第三范式的,应该在设计文档中明示原因,并说明如何保持数据的一致性。
1 命名规范
(1) 数据库名、表名、字段名必须使用小写字母,并采用下划线”_”分割。
(2) 数据库名、表名、字段名禁止超过32个字符,须见名知意,建议使用名词不是动词。
(3) 数据库名、表名、字段名禁止使用MySQL保留字。
(4) 临时库名、表名必须以tmp为前缀,并以日期为后缀。
(5) 备份库名、表名必须以bak为前缀,并以日期为后缀。
2 基础规范
(1) 使用INNODB存储引擎
(2) 表字符集使用UTF8
(3) 所有表都需要添加注释
(4) 单表数据量建议控制在5000W以内
(5) 数据库表建议不存储图、文件等大数据
(6) 禁止在线上做数据库压力测试操作
(7) 所有字段须定义为not null,根据业务可指定default值
3 库表设计
(1) 库名格式为 组织机构_xxx[xxx],比如以toon基础为例,其中“toon”为前缀,xxx为实际数据库名称,使用各模块的项目名称字段设计。
(2) 表名中含有单词全部采用单数形式,多个单词之间使用”_”分割
(3) 同业务模块表,建议在表名前增加模块缩写。
示例:客户表:cust_customer
客户联系方式:cust_contact
(4) 分表命名规则:原表明_数字,示例:cust_customer _01
(5) 所有表添加注释。
(6) 所有表必须要显式指定主键。
(7) 单表控制字段数量,30个字段的上限。
(8) 单表数据量建议控制在2000W~5000W以内
简单字段类型建议 5000W以内,比如int,tinyint,bigint等
复杂字段类型建议 2000W 以内,比如varchar(n>2048),text等
(9) 关联表命名规则:表a_表b,如果存在模块缩写,根据实际的业务需要保留一个模块缩写
示例:
房客关系表: prt_property_customer
4 字段设计
类型 字节 有/无符号 最小值 最大值
TINYINT 1 有 -128 127
无 0 255
SMALLINT 2 有 -32768 32767
无 0 65535
MEDIUMINT 3 有 -8388608 8388607
无 0 16777215
INT 4 有 -2147483648 2147483647
无 0 4294967295
BIGINT 8 有 -9223372036854775808 9223372036854775807
无 0 18446744073709551615
(1) 越小越好的原则,选择合适的数据类型,数据类型所占用字节数越小越好;数值类型取值参考下表:
如主键取值上限不超过42亿,建议不用BIGINT
(2) 越简单越好的原则,字段能用数值型的不要用字符型。
(3) 尽量避免使用 text/blob数据类型, 若确实需要,根据访问, 更新频次, 看是否有必要从 主表拆分出来。
(4) 使用TINYINT代替ENUM、SET。
(5) 字符串类型,比较小并且固定比如MD5值等选择CHAR,否则选择VARCHAR。
使用尽可能小的VARCHAR字段,VARCHAR(N)中的N表示的是字符数而非字节数,一个汉字占用三个字节,一个字母占用一个字节。
(6) 字段须指定NOT NULL。
(7) 常用字段类型推荐
id主键:bigint或int,视数据增长范围选择,自增;
phone:varchar(15);
email:varchar(254);
邮编:varchar(11);
枚举型数据:tinyint;
url:varchar(2083);
img:varchar(2083);
IP:varchar(45)或转整型存储;
Money:DECIMAL(19,4);
Longitude:DECIMAL(9,6);
Latitude:DECIMAL(8,6)。
5 索引设计
(1) 非唯一索引必须按照“idx_字段名称_字段名称[_字段名]”进行命名。
(2) 唯一索引必须按照“uniq_字段名称_字段名称[_字段名]”进行命名。
(3) 控制索引数量,单表索引数量不超过5个,单个索引字段不超过5个。
(4) 索引尽量健在区分度性高的列上,不在低区分度列上建立索引,例如性别。
(5) 不要在频繁更新的列上建索引,不在索引列进行数学运算和函数运算。
(6) 合理创建联合索引(避免冗余),(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c)
(7) 重要的SQL必须被索引,UPDATE、DELETE语句的WHERE条件列,ORDER BY、GROUP BY、DISTINCT的字段,多表JOIN的字段
(8) 不使用%前缀的查询,如like “%ab”;不使用负向查询,如not in/like(推荐考虑用全文检索sphinx)。
6 SQL设计
(1) sql语句尽可能简单,大的sql根据业务拆分成小的sql语句(充分利用QUERY CACHE和充分利用多核CPU)。
(2) limit分页注意效率。limit越大,效率越低。可以改写limit,比如例子改写:select id from t limit 10000, 10; => select id from t where id > 10000 limit10。
(3) 减少与数据库的交互次数,尽量使用批量sql语句。
(4) 注意使用性能分析的工具
Sql explain / showprofile / mysqlsla
(5) 建议SQL关键字全部是大写,每个词只允许有一个空格
(6) SQL语句不可以出现类型隐式转换,比如 select id from 表 where id='1'
(7) IN条件里面的数据数量要少,使用exist代替in,exist在一些场景查询会比in快
在两个都可以使用的情况下,建议通过执行计划来做取舍。
(8) 禁止在数据库中跑大查询
(9) 能不用NOT IN就不用NOT IN。
(10) 在SQL语句中,不建议使用模糊前缀匹配操作,比如like
(11) 关于分页查询:程序里建议合理使用分页来提高效率limit,offset较大要配合子查询使用
(12) 使用预编译语句,只传参数,比传递SQL语句更高效;一次解析,多次使用;降低SQL注入概率
7 行为规范
(1) 数据库设计须有DBA参与,表结构变更必须通知DBA;
(2) 批量导入、导出或者批量更新数据,必须DBA进行审核,执行;
(3) 建议对同一个表的多次alter操作合并为一次操作;
(4) 不要在MySQL数据库中存放业务逻辑;
(5) 建议禁止存储过程、函数、触发器的使用。
7、常用命令
1、删除所有匿名用户
mysql> DROP USER ''@'localhost';
mysql> DROP USER ''@'www.xxx.com';
用户帐号由两部分组成:username@host
host还可以使用通配符:
%: 任意长度的任意字符
_: 匹配任意单个字符
2、给所有的root用户设定密码:
第一种方式:
mysql> SET PASSWORD FOR username@host = PASSWORD('your_passwrod');
第二种方式:
mysql> UPDATE user SET password = PASSWORD('your_password') WHERE user = 'root';
mysql> FLUSH PRIVILEGES;
第三种方式:
# mysqladmin -uUserName -hHost password 'new_password' -p
# mysqladmin -uUserName -hHost -p flush-privileges
创建新用户# 创建用户和设置密码
CREATE USER '新用户'@'localhost' IDENTIFIED BY '新密码';
对用户授权
GRANT ALL PRIVILEGES ON . TO '新用户'@‘localhost' WITH GRANT OPTION;
连入MySQL服务器
mysql client <--mysql protocol--> mysqld
mysqld接收连接请求:
本地通信:客户端与服务器端位于同一主机,而且还要基于127.0.0.1(localhost)地址或lo接口进行通信;
Linux OR Unix: Unix Sock, /tmp/mysql.sock, /var/lib/mysql/mysql.sock
Windows: memory, pipe
远程通信:客户端与服务器位于不同的主机,或在同一主机便使用非回环地址通信
TCP socket
客户端工具:mysql, mysqladmin, mysqldump, mysqlcheck
[client]
通行的选项:
-u, --user=
-h, --host=
-p, --password=
--protocol={tcp|socket|memory|pipe}
--port=
--socket= 例如:/tmp/mysql.sock
【注意格式-u和-p后没有空格是连在一起的,如果密码想要不显示可以这样:mysql -uroot -p 回车输入密码】
mysql监听的端口: 3306/tcp
非客户端类的管理工具:myisamchk, myisampack
mysql工作模式:
交互式模式
mysql>
脚本模式
mysql < /path/to/mysql_script.sql
mysql交互式模式:
客户端命令
mysql> help
mysql> \?
\c
\g
\G
\q
\!
\s
\. /path/to/mysql_script.sql
服务器端命令:需要命令结束符,默认为分号(;)
mysql> help contents
mysql> help Keryword
mysql命令行选项:
--compress
--database=, -D
-H, --html:输出结果为html格式的文档
-X, --xml: 输出格式为xml
--sate-updates: 拒绝使用无where子句的update或delete命令;
mysql命令提示符:
mysql> 等待输入命令
->
'>
">
`>
/*>
mysql的快捷键:
Ctrl + w: 删除光标之前的单词
Ctrl + u: 删除光标之前至命令行首的所有内容
Ctrl + y: 粘贴使用Ctrl+w或Ctrl+u删除的内容
Ctrl + a: 移动光标至行首
Ctrl + e: 移动光标至行尾
8、MySQL优化
MySQL优化需要在三个不同层次上协调进行:MySQL级别、OS级别和硬件级别。MySQL级别的优化包括表优化、查询优化和MySQL服务器配置优化等,而MySQL的各种数据结构又最终作用于OS直至硬件设备,因此还需要了解每种结构对OS级别的资源的需要并最终导致的CPU和I/O操作等,并在此基础上将CPU及I/O操作需要尽量降低以提升其效率。
数据库层面的优化着眼点:
1、是否正确设定了表结构的相关属性,尤其是每个字段的字段类型是否为最佳。
2、是否为高效进行查询创建了合适的索引。
3、是否为每张表选用了合适的存储引擎,并有效利用了选用的存储引擎本身的优势和特性。
4、是否基于存储引擎为表选用了合适的行格式(row format)。
5、是否使用了合适的锁策略,如在并发操作场景中使用共享锁,而对较高优先级的需求使用独占锁等。
6、是否为InnoDB的缓冲池、MyISAM的键缓存以及MySQL查询缓存设定了合适大小的内存空间,以便能够存储频繁访问的数据且又不会引起页面换出。
操作系统和硬件级别的优化着眼点:
1、是否为实际的工作负载选定了合适的CPU,如对于CPU密集型的应用场景要使用更快速度的CPU甚至更多数量的CPU,为有着更多查询的场景使用更多的CPU等。因为MySQL尚不能高效的运行于多CPU,并且其对CPU数量的支持也有着限制。一般来说,较新的版本可以支持16至24颗CPU甚至更多。
2、是否有着合适大小的物理内存,并通过合理的配置平衡内存和磁盘资源,降低甚至避免磁盘I/O。缓存可以有效地延迟写入、优化写入,但并能消除写入,并综合考虑存储空间的可扩展性等,为业务选择合理的外部存储设备也是非常重要的工作。
3、是否选择了合适的网络设备并正确地配置了网络对整体系统系统也有着重大影响。延迟和带宽是网络连接的限制性因素,而常见的网络问题如丢包等,即是很小的丢包率也会赞成性能的显著下降。而更重要的还有按需调整系统中关于网络方面的设置,以高效处理大量的连接和小查询。
4、是否基于操作系统选择了适用的文件系统。同时,关闭文件系统的某些特性如访问时间和预读行为,并选择合理的磁盘调度器通常都会给性能提升带来帮助。
5、MySQL为响应每个用户连接使用一个单独的线程,再加内部使用的线程、特殊目的线程以及其它任何由存储引擎创建的线程等,MySQL需要对这些大量线程进行有效管理。Linux系统上的NPTL线程库更为轻量级也更有效率。MySQL 5.5引入了线程池插件,但其效用尚不明朗。
跟阿里云数据库大佬电话沟通 and Google解决方案 and 问群里大佬,总结如下(都是精华):
1.数据库设计和表创建时就要考虑性能
2.sql的编写需要注意优化
3.分区 【MySQL在5.1版引入的分区是一种简单的水平拆分,用户需要在建表的时候加上分区参数,对应用是透明的无需修改代码】
4.分表 【分表就是把一张大表,按照如上过程都优化了,还是查询卡死,那就把这个表分成多张表,把一次查询分成多次查询,然后把结果组合返回给用户。】
5.分库 【把一个数据库分成多个,建议做个读写分离就行了,真正的做分库也会带来大量的开发成本,得不偿失!不推荐使用。】
第一优化sql和索引;
第二加缓存,memcached,redis;
第三以上都做了后,还是慢,就做主从复制或主主复制,读写分离,可以在应用层做,效率高,也可以用三方工具,第三方工具推荐360的atlas,其它的要么效率不高,要么没人维护;
第四如果以上都做了还是慢,不要想着去做切分,mysql自带分区表,先试试这个,对你的应用是透明的,无需更改代码,但是sql语句是需要针对分区表做优化的,sql条件中要带上分区条件的列,从而使查询定位到少量的分区上,否则就会扫描全部分区;
第五如果以上都做了,那就先做垂直拆分,其实就是根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
第六才是水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key,为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;
优化相关参数:
查询mysql跑在哪颗cpu上一个进程只能跑在一个CPU上
mysql 详解
查询缓存流程图:
mysql 详解
开启缓存
mysql > show variables like '%query%'; 查询缓存
set global query_cache_size =16777216; 改查询缓存
mysql 详解
慢速查询日志
mysql 详解
打开表动作缓存
mysql 详解
连接数调整
mysql 详解
缓存innidb表空间 【默认8M 理论越大越好 设置整体内存80%】
mysql 详解
连接超时时间 【当网络通信情况不好或后端机负载大时,这个数值往大调,不然会造成很多前端机连不上】
mysql 详解
查看innodb事务日志方式 【这个值对IO影响特别大,决定innodb事务日志往磁盘写的方式数值只有0 1 2 (建议改成2)】
mysql 详解
查询相关的状态变量
mysql 详解
缓存命中率的评估:Qcache_hits/(Qcache_hits+Com_select)
9、总结
数据分析离不开SQL工具,SQL的使用能力是数据分析的一项基础能力,这就是学习SQL最核心的原因,只要你有从事数据分析的想法,就必须踏踏实实去学习。《大数据时代》是我看的第一本关于网络趋势的书,它从宏观层面把握这个时代,从“大数据”这一时代特征着手,讲述了大数据对我们生活,工作,乃至思维的变革。具体包括:大数据的概念,它的价值,它带来的转变及转变的方式,它的负面影响,这个时代的一系列规范等。在今天大数据盛行的时代,NoSQL:redis, mongodb, hbase, NewSQL:TiDB、关系型数据库MySQL都在每个业务层次发挥着重要的作用。不管是大数据还是小数据,掌握一套数据管理系统是必要的,当下的MySQL在开源界还是比较流行的,就连一些国企也开始在去IOE,所以还是有深入学习的必要,本着以温故而知新的目的,把MySQL相关知识循序渐进的梳理成新篇章。