mysql数据库回顾 ——致敬狂神

压缩版安装

mysql5.7版本的压缩包下载链接
链接: https://pan.baidu.com/s/1qCxsisX_IDs-1j19fiLpzg提取码: ktm5

  • 解压到指定目录,例如mysql数据库回顾 ——致敬狂神_第1张图片
  • 配置环境变量,右键单击我的电脑,选择属性。然后如下图(路径要和解压的位置保持一致)
    mysql数据库回顾 ——致敬狂神_第2张图片
  • 进入解压目录创建my.ini初始化配置文件
[mysqld]
basedir=D:\mysql-5.7.23\
datadir=D:\mysql-5.7.23\data\
port=3306
skip-grant-tables #初次登录不用输入密码
  • 管理员权限打开cmd,进入到 mysql目录的bin目录下 输入mysqld -install然后回车执行安装。
  • 成功安装之后(上一步会有提示)输入mysqld --initialize-insecure --user=mysql然后回车执行。这个动作就是在完成初始化操作,会根据我们创建my.ini文件来。命令行不报错,等待下一个指令时,一般就初始化完成了。
  • 然后输入 net start mysql回车执行,启动mysql服务。成功后会有提示。
  • 然后我们首次输入mysql -uroot -p直接回车,会让输入密码,此时我们没有密码,再次回车。就进去了。可以发现命令行提示变成了mysql
  • 然后输入update mysql.user set authentication_string=password(‘123456’) where user=‘root’ and Host = ‘localhost’;回车执行,会将密码修改为123456 。然后输入flush privileges;回车执行,使改动生效。然后我们回到my.ini文件,把最后一行skip开头的注解掉,前面加个#号就ok了,加完后记得保存。
  • 然后我们退出mysql,执行exit会提示bye,我们重启下mysql服务,输入 net stop mysql执行。然后输入 net start mysql回车执行。这时候我们再次登录数据库就需要使用我们刚才的密码了。

建表模板

CREATE TABLE IF NOT EXISTS `student` (
  `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
  `name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
  `pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
  `sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
  `birthday` DATETIME NULL COMMENT '出生日期',
  `address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
  `email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
  PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

--  数据库引擎
INNODB   -- 默认使用
MYISAM   -- 早些年使用
--
数据库引擎 INNODB MYISAM
事务 支持 不支持
数据行锁定 支持 不支持
外键约束 支持 不支持
全文索引 不支持 支持
表空间的大小 较大,约为2倍 较小

修改表

ALTER TABLE `teacher` RENAME AS `teacher1` -- 修改表名
ALTER TABLE `teacher1` ADD age INT(11) -- 增加表字段
ALTER TABLE `teacher1` MODIFY age VARCHAR(10) -- 修改表字段约束
ALTER TABLE `teacher1` CHANGE age age1 INT(2) -- 修改表字段名称

ALTER TABLE `teacher1` DROP age1 -- 删除表字段
DROP TABLE IF EXISTS `teacher1` -- 删除表

外键

ALTER TABLE `student` ADD gradeid INT(2)

CREATE TABLE `grade` (
  `gradeid` INT(2) PRIMARY KEY NOT NULL AUTO_INCREMENT COMMENT '年级id',
  `name` VARCHAR(10) NOT NULL COMMENT '年级名称'
)ENGINE=INNODB DEFAULT CHARSET=utf8

ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`)

阿里 规范不允许使用 外键 级联,这样会使数据库操作极为麻烦
要求 外键的关系 在应用层去解决 即java代码中去解决

数据库语言

DDL 定义
DML 管理
DQL 查询
DCL 控制

insert into 表名(列名1, 列名2, 列名3)
         values ('值1','值2','值3'),
                ('值1','值2','值3')

update 表名
   set 列名1 = '值1', 
       列名2 = '值2', 
       列名3 = '值3'
 where 条件

delete from 表名
      where 条件

#concat() 拼接函数
select concat(a, b) [as '别名']
  from 表名 [as '别名']
[where 条件]

join on  # 连接查询
where    # 等值查询
操作 描述
inner join 查询两张表中任一表包含的 目标字段值
left join 返回左表包含的 目标字段值 即使右表中 不含该记录
right join 返回右表包含的 目标字段值 即使左表中 不含该记录

select 语法

select [all | distinct]
{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
from table_name [as table_alias]
	[left | right | inner join table_name2] -- 联合查询
	[where ...] -- 指定结果需满足的条件
	[group by ...] -- 指定结果按照哪几个字段来分组
	[having ...] -- 过滤分组的记录必须满足的次要条件
	[order by ...] -- 指定查询记录按一个或多个条件排序
	[limit {[offset,]row_count | row_countOFFSET offset}] ; 
	-- 指定查询的记录从哪条到哪条

注意:[ ]括号代表可选的,{ }括号代表必选的
group by 后的条件过滤只能用having 不能用where

事务举例

CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci 
USE shop   
   
CREATE TABLE `account` (
  `id` INT(3) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(30) NOT NULL,
  `money` DECIMAL(9,2) NOT NULL,
  PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8 
 
 INSERT INTO `account`(`name`, `money`) VALUES ('A', 800.00),('B', 200.00)
 
 UPDATE `account` SET `money` = 2000.00 WHERE id = 1
 UPDATE `account` SET `money` = 10000.00 WHERE id = 2
 
 SET autocommit = 0; -- 关闭自动提交
 START TRANSACTION  -- 开始一个事务 (一组事务)
 
 UPDATE `account` SET `money` = `money` - 500 WHERE `name` = 'A'; -- A减500
 UPDATE `account` SET `money` = `money` + 500 WHERE `name` = 'B'; -- B加500

 COMMIT    -- 提交
 ROLLBACK  --  回滚
 
 SET autocommit = 1; -- 恢复自动提交

事务 四要素acid

要素 特点
原子性(automicity) 事务内部的操作不可分割, 全成功(commit)或全失败(rollback)
一致性 (consistency) 事务的前后,整体状态保持一致 (如事务前A,B共12000,事务后也必须12000)
隔离性 (isolation) 事务与事务之间,应相互隔离执行互不影响 (避免 xxx读)
持久性 (durability) 事务一旦提交,则数据永久化

脏读

一个事务读取了另一个事务还未提交的数据

不可重复读

一个事务内 多次读取 发现 有数据被其他事务修改过

幻读(虚读)

一个事务内 多次读取 读到了另一个事务插入的新数据

索引

alter table 表名 add fulltext index 索引名(列名);

explain select * from student  -- explain关键字分析sql执行情况

explain select * from student where match('studentname') against('刘');

建表

drop table if exists `app_user`;
CREATE TABLE `app_user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT '',
  `eamil` varchar(50) NOT NULL,
  `phone` varchar(20) DEFAULT '',
  `gender` tinyint(4) unsigned DEFAULT '0',
  `password` varchar(100) NOT NULL DEFAULT '',
  `age` tinyint(4) DEFAULT NULL,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `id_app_user_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1000002 DEFAULT CHARSET=utf8

创建插入100万行随机数据的函数

DELIMITER $$

USE `school`$$   -- 注意要有这个数据库

DROP FUNCTION IF EXISTS `mock_data`$$

CREATE DEFINER=`root`@`localhost` FUNCTION `mock_data`() RETURNS INT(11)
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO `app_user`(`name`,`eamil`,`phone`,`gender`,`password`,`age`) 
VALUES (CONCAT('用户',i),'[email protected]',CONCAT('18',FLOOR(RAND()*(999999999-100000000)+100000000))
,FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
SET i=i+1;
END WHILE;
RETURN i;
END$$

DELIMITER ;

测试效果

SELECT * FROM app_user WHERE `name` = '用户9999'; -- 1.148 sec
SELECT * FROM app_user WHERE `name` = '用户9999'; -- 1.283 sec
SELECT * FROM app_user WHERE `name` = '用户9999'; -- 1.222 sec

EXPLAIN SELECT * FROM app_user WHERE `name` = '用户9999';  -- 找了992391条数据才找到   无索引

CREATE INDEX id_app_user_name ON app_user(`name`); -- 创建一个索引   11.674 sec

SELECT * FROM app_user WHERE `name` = '用户9999'; -- 执行耗时: 0 sec   传送时间: 0.002 sec    总耗时: 0.002 sec    建立索引后

用户管理

grant all privileges *.* to kuangshen   -- 授予所有权限   但不包含 grant option

revoke all privileges *.* from kuangshen  -- 撤销所有权限

数据库备份

导出:mysqldump -h主机名 -u用户名 -p密码 数据库名 表名(多个时空格隔开) > 磁盘位置+文件名.sql

mysqldump -hlocalhost -uroot -p123456 school student > D:/a.sql

导入:source 磁盘位置+文件名.sql

# 先链接数据库
mysql -uroot -p123456

#使用数据库
use school

#执行表的导入
source D:/a.sql

#还可以直接来
mysql -uroot -p123456 school < D:/a.sql

数据库设计

1.分析需求
2.落实实体表
3.分析实体表之间的关系

数据库三大范式

第一范式(1NF)
原子性: 保证每一列的含义不可再分 (家庭信息:(地址,人口数 ) -> 分为 2列才对)
第二范式(2NF)
前提:满足 第一范式
每张表只描述一件事情 。。。。。。
第三范式(3NF)
前提:满足 第一范式 和 第二范式
消除列之间的传递依赖

可以直观的感受到 范式会导致表的疯狂细分

实际生产环境 规范性和性能问题
阿里标准: 关联查询的表不得超过三张
以用户体验和性能为主 适当考虑 范式
例如: 某些冗余列 可以 消除 多表链接查询

对MySQL索引的一点儿挖掘

学习文章http://blog.codinglabs.org/articles/theory-of-mysql-index.html

首先我们需要知道 系统内存读写 和磁盘读写的速度是有很大差异的

然后磁盘读写会具有一些特质。
磁盘I/O, 由磁头和磁盘来完成,磁头读取磁盘的信息。

  • 磁头延磁盘的斜切线运动(磁盘是圆的,为了找到中间的小扇区,或者外侧的大扇区),称为:寻道
  • 磁盘圆片旋转(配合磁头找到相应的扇区),称为:旋转

这二个动作是产生磁盘I/O时,会发生在机器上的物理动作,所以相对而言会非常耗时。

  • 局部性原理
    一个数据被用到时,其附近的数据也通常马上会被使用
  • 磁盘预读
    当产生了哪怕一个字节的读取时,计算机将从这个位置开始,按 页(页是计算机管理存储器的逻辑块) 为单位,向后读取一页或几页数据到内存中。 预读时,磁头只需要寻道一次,然后磁盘旋转即可完成。这样就极大的节省了I/O时间。
另外我们还需要了解,数据结构中的一种结构:树。但不是二叉树(哈哈哈)是BTree

mysql数据库回顾 ——致敬狂神_第3张图片
mysql数据库回顾 ——致敬狂神_第4张图片
描述读起来有些晦涩。。
这种树的特点是:

  • 每个节点保存一段数据
  • 节点中交替出现key值(视为int理解就好)区和指针区,
  • 节点中的key值,从左往右是非递减的。(通俗理解从左往右逐渐变大)
  • 两个key值区之间的指针,指向的下一个节点中包含的所有key值,就在两个key值的范围内!

B-Tree和B+Tree的区别(对着图看还挺直观的)

  • +树把每个节点的首位置的指针区去掉了
  • +树把每个非叶子节点的key值下的数据区去掉了
  • +树的叶子节点不包含key值区

然后数据库或文件系统采用B+Tree实现索引的时候,会再做一点修改,在叶节点之间添加顺序访问指针
mysql数据库回顾 ——致敬狂神_第5张图片

BTree这样的结构,就刚好可以,把叶节点的大小设置为磁盘扇区 页 的大小,这样吻合后,一个叶节点中值的访问,就只需要一次I/O操作了

了解了这些东西,我们再看mysql数据库两种常见的引擎。对于索引的实现。MyISAM,和InnoDB

MyISAM的B+Tree实现,叶节点中data存储的是真实数据区的内存地址,索引得到的结果是目标值的内存地址,然后需要到对应地址获取值。
InnoDB的B+Tree实现,叶节点中data域保存了完整的数据记录,当前索引的key就是数据表的主键,
因此InnoDB表数据文件本身就是主索引。

所以,mysql数据库 使用InnoDB引擎创建的数据库,里面的数据表必须要有主键,不显示的设置主键,也会底层默认使用一个唯一列来作为主键。

上面所说的一堆特性, 应用起来表示为

一定要让每个表的索引都建立在一个 自增的主键列上,这样才能有效利用 局部性原理 提高读写效率。
另外索引是一个独立存在的结构,也会占用内存,所以不要使用过长的数据列建立索引,若有必要,就采用最左前缀去创建索引,这个前缀的长度,需要根据 选择性 来确定

Index Selectivity = Cardinality / #T
显然选择性的取值范围为(0, 1],选择性越高的索引价值越大,这是由B+Tree的性质决定的

SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles;

另外说一些,索引失效的场景

  • where子句中包含了or时
  • 使用like模糊匹配时,以%开头
  • 使用了函数或者表达式时
  • 组合索引,条件里面未指定索引的第一列

你可能感兴趣的:(致敬狂神)