关系型数据库RDBMS
全称:Relational Database Management System
数据的分类
冷数据
是对于离线类不经常访问的数据,比如备份数据、档案与操作日志数据、话单凭证与统计数据。冷数据不需要实时访问到离线数据,
用于灾难恢复的备份或者因为要遵守法律规定必须保留一段时间的。
热数据
是需要被计算节点频繁访问的在线类数据。指即时的位置状态、交易和浏览行为。
温数据
是非即时的状态和行为数据。简单理解把热数据和冷数据混在一起就成了温数据。
冷数据存储在磁带、光盘,目前发展比较好的是蓝光光盘。热数据一般存放在SSD中,存取速度快,而温数据可以存放在7200转的硬盘
数据的切分
关系型数据库瓶颈 | 详情 |
CPU | 高并发场景 连接数 |
磁盘I/O | 单机的存储容量 海量数据读写 |
单表最大记录数超过多少时性能会严重下降?
根据阿里巴巴的Java开发手册,单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。但是,如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
垂直切库-分库 | 垂直切表-分表 | 水平切分-分区 | |
切分对象 | 表 | 表中字段 | 表中数据 |
应用场景 | 单个物理数据库的资源跟连接数是有限制的 | 字段过多导致跨页,消耗资源 | |
优点 | 一定程度上提升了数据库性能 | ||
缺点 | 单表的数据量还是会很大。 | 单表的数据量还是会很大。 |
垂直切分
垂直切库-分库
切分对象:表。
应用场景:单个物理数据库的资源跟连接数是有限制的。
同机器 | 不同机器 | |
优点 | ||
缺点 |
垂直切表-分表
切分对象:表中字段。
应用场景:数据库以行为单位将数据加载到内存中,1)一条记录占用空间过大会导致跨页。2)内存能加载更多的数据,命中率更高,减少了磁盘IO
同机器 | 不同机器 | |
优点 | ||
缺点 |
优点:一定程度上提升了数据库性能。
缺点:单表的数据量还是会很大。
避免跨页问题,MySQL底层是通过数据页存储的,一条记录占用空间过大会导致跨页,造成额外的性能开销。另外数据库以行为单位将数据加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升了数据库性能。
水平切分-分区
切分对象:表中数据。
应用场景:单表数据量达到百万或千万级别,数据量行数巨大,存在单库读写、存储性能瓶颈。
同机器 | 不同机器 | |
优点 | 单表的数据量降低 | 单表的数据量降低 |
缺点 | 连接数是有限制 |
范围分区
对某个值进行分区,如日期
CREATE TABLE 表名()PARTITION BY RANGE(字段)( PARTITION 分区名 VALUES LESS THAN(分区值) );SELECT * FROM 表 PARTITION(分区名);
列表分区
应用于重复性高的数据;数据管理能力较强,但数据分布可能不均匀
create table 表名()partition by list(字段)( partition 分区名 values(分区值));select * from 表 partition(分区名);
哈希分区
应用于重复性低的数据;数据分布较为均匀。
分区数一般为2的幂,适用于静态数据,数据管理能力弱
CREATE TABLE 表名()PARTITION BY HASH(字段)( PARTITION 分区名);SELECT * FROM 表 PARTITION(分区名);
复合分区
范围-列表分区
CREATE TABLE 表名()PARTITION BY RANGE(字段)SUBPARTITION BY LIST(字段)SUBPARTITION template ( SUBPARTITION 分区名2 VALUES (分区值))( PARTITION 分区名1 VALUES LESS THAN(分区值) )SELECT * FROM 表 PARTITION(分区名);SELECT * FROM 表 SUBPARTITION(子分区名);子分区名 = 分区名1+分区名2
范围-哈希分区
CREATE TABLE 表名()PARTITION BY RANGE(字段)subpartition by hash(字段) ( PARTITION 分区名 VALUES LESS THAN(分区值) ( subpartition 子分区名 ));SELECT * FROM 表 PARTITION(分区名);SELECT * FROM 表 SUBPARTITION(子分区名);
中间件
分库分表
问题:
用户请求量太大。单服务器TPS、内存、IO都是有上限,需要将请求打散分布到多个服务器。
单库数据量太大。单个数据库处理能力有限;单库所在服务器的磁盘空间有限;单库上的操作IO有瓶颈。
单表数据量太大。查询、插入、更新操作都会变慢,再加字段、索引、机器迁移都会产生高负载,影响服务
使用后的问题
事物管理
join
数据扩容
读写分离
使用场景:读远大于写,数据实时性要求不高。
将对数据库的读写操作分散到不同的数据库节点上。
读写分离能够小幅提升写性能,大幅提升读性能。
一主多从 | 数据库操作 |
主库 | 写(insert update delete)操作 |
从库 | 读(select) |
。。。 | 读(select) |
从库 | 读(select) |
主库和从库之间会进行数据同步,以保证从库中数据的准确性。这样的架构实现起来比较简单,并且也符合系统的写少读多的特点。
Master my.cnf 配置:
binlog-do-db=tlshop
binlog-ignore-db=mysql
binlog_format=mixed
log-bin=mysql-bin
server-id=1
Slave my.cnf 配置
replicate-do-db=tlshop
replicate-ignore-db=mysql
server-id=2
#以下的配置是5.6 之前版本
#master-host=192.168.0.15
#master-port=3306
#master-user=root
#master-password=123456
主从复制
基于代理层
mycat代理
Mycat 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库
Sharding-Proxy
基于应用层
Sharding-JDBC
基于 JDBC 接口的扩展,是以 jar 包的形式提供轻量级服务的。
Sharding-Sphere,sharding-jdbc、Sharding-Proxy、Sharding-Sidecar
Sharding-JDBC Sharding-Proxy Sharding-Sidecar
Database Any MySQL MySQL
Connections Cost More Less More
Heterogeneous Language Java Only Any Any
Performance Low loss High loss Low loss
Centre-less Yes No No
Static Entry No Yes No
数据库
数据库文件 | |
mdf | 主数据文件,有且只有一个。 |
ndf | 次要数据文件,0到多个。 |
idf | 日志文件,一个以上。 |
逻辑结构
表空间
Oracle数据库真正存放数据的是数据文件(Data File),oracle表空间(tablespace)实际上是一个逻辑的概念,在物理上是并不存在的,那么把一组data files捻在一起就成为一个表空间。
表空间属性:
一个数据库可以包含多个表空间,一个表空间只能属于一个数据库
一个表空间包含多个数据文件,一个数据文件只能属于一个表空间
在创建用户的时候,为其指定表空间,最后不同的用户持有不同的表空间(当多人做同一项目时,可以使用同一表空间),如果没有指定表空间,用户就会默认使用system的表空间,不利于用户对数据进行持有和管理。
在表空间没有被删除的情况下,不能再物理上移除表空间对应的数据文件。
--------------------------------创建默认表空间--------------------------------
CREATE TABLESPACE 默认表空间
--创建默认表空间
DATAFILE '绝对路径\临时表.dbf'
--文件夹路径需提前指定
SIZE xxxM
--初始大小xxxM
AUTOEXTEND ON
--自动扩展
NEXT yyyM
--每次增加yyyM
MAXSIZE zzzM;
--最大可到zzzM
-------------------------------- 创建临时表空间--------------------------------
CREATE TEMPORARY TABLESPACE 临时表
--创建临时表
TEMPFILE '绝对路径\临时表.dbf'
--文件夹路径需提前指定
SIZE xxxM
--初始大小xxxM
AUTOEXTEND ON
--自动扩展
NEXT yyyM
--每次增加yyyM
MAXSIZE zzzM;
--最大可到zzzM
--------------------------------创建资源文件 --------------------------------
CREATE PROFILE 资源文件名 LIMIT
FAILED_LOGIN_ATTEMPTS X
--指定用户登录失败次数X
PASSWORD_LOCK_TIME Y
--指定用户失败被锁定天数Y
PASSWOED_LIFE_TIME Z;
--指定用户可用权限天数Z
--------------------------------创建用户指定表空间 --------------------------------
CREATE USER 用户名 IDENTIFIED BY 密码 DEFAULT
TABLESPACE 默认表
TEMPORARY TABLESPACE 临时表
PROFILE 资源文件名
--------------------------------删除表空间 --------------------------------
--第一步:指定用户
DROP USER 用户名;
--第二步:删除默认表空间,临时表空间,资源文件
DROP TABLESPACE 默认表;
DROP TEMPORARY TABLESPACE 临时表;
DROP PROFILE 资源文件名;
数据库表设计
1)需求分析: 分析用户的需求,包括数据、功能和性能需求;
2)概念结构设计:主要采用E-R模型进行设计,包括画E-R图;
3)逻辑结构设计:通过将E-R图转换成表,实现从E-R模型到关系模型的转换,进行关系规范化;
4)数据库物理设计:主要是为所设计的数据库选择合适的存储结构和存储路径;
5)数据库的实施:包括编程、测试和试运行;
6)数据库运行和维护:系统的运行和数据库的日常维护。
表设计的三大范式
需求>性能>表结构。
第一范式:列的原子性。简记为1NF。
第二范式:所有列都与主键有关,无部分依赖。简记为2NF。
第三范式:所有列都与主键直接相关,无部分依赖,无传递依赖。简记为3NF。
createuser.sql
modifydate.sql
createdate.sql
state.sql
modifyuser.sql
E-R实体关系图
实体 - 矩形
属性 - 椭圆
实体之间 - 菱形
一对一:一个表
一对多:两个表
多对多:三个表
锁
按照锁的粒度把数据库锁分为表级锁和行级锁
表锁
对当前操作的整张表加锁,实现简单 ,资源消耗也比较少,加锁快,不会出现死锁 。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
虽然使用行级索具有粒度小、并发度高等特点,但是表级锁有时候也是非常必要的:
- 事务更新大表中的大部分数据直接使用表级锁效率更高;
- 事务比较复杂,使用行级索很可能引起死锁导致回滚。
行锁
对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。 InnoDB支持的行级锁,包括如下几种算法。
Record Lock
对索引项加锁,锁定符合条件的行。
其他事务不能修改和删除加锁项;Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。理解成单个行记录上的锁。
Gap Lock
对索引项之间的“间隙”加锁,锁定记录的范围(对第一条记录前的间隙或最后一条将记录后的间隙加锁),不包含索引项本身。
其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。
Next-key Lock
锁定索引项本身和索引范围。
锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。即Record Lock和Gap Lock的结合。可解决数据库幻读问题。Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在Next-Key Lock算法下,InnoDB对于行的查询都是采用这种锁定算法。例如有一个索引有10,11,13和20这4个值,那么该索引可能被Next-Key Locking的区间为:
SQL语言
数据定义DDL(用户/数据库/表)
英文全称:Data Definition Language
CREATE创建
-- 创建表
CREATE TABLE IF NOT EXISTS 表 (
字段 数据类型 约束 COMMENT '字段备注',
CREATE_DATE DATETIME DEFAULT NULL COMMENT '创建时间',
CREATE_USER int(6) NOT NULL COMMENT '创建用户',
MODIFY_DATE DATETIME DEFAULT NULL COMMENT '修改时间',
MODIFY_USER int(6) NOT NULL COMMENT '修改用户',
STATE char(1) NOT NULL COMMENT '状态',
PRIMARY KEY (字段)
) ENGINE=存储引擎 AUTO_INCREMENT=自增初始值 DEFAULT CHARSET=编码格式;
ALTER更新
-- 表添加字段
ALTER TABLE 表 ADD(字段);
-- 表修改字段
ALTER TABLE 表 modify(字段);
-- 表删除字段
ALTER TABLE 表 DROP(字段);
-- 修改用户密码
ALTER USER 用户名 IDENTIFIED BY 新密码
DROP删除
-- 删除数据对象
DROP TABLE IF EXISTS 表/视图
TRUNCATE截断
DELETE FROM 表 WHERE 条件;
TRUNCATE TABLE;
-- 保留表,删除表中所有记录能把自动递增值的字段做计数重置归零重新计算。TRUNCATE TABLE 比 DELETE 速度快。
SHOW查看
角色ROLE
-- 创建角色
create role 角色名
用户USER
-- 创建用户
CREATE USER 用户名 identified by 密码;
-- 删除用户
DROP USER 用户名;
-- 修改用户
ALTER USER 用户名 identified by 新密码;
-- 查看用户权限
SHOW grants for 用户名;
-- 查看当前所有连接用户
show full processlist;
-- 查看所有用户
SELECT * FROM mysql.user;
SELECT DISTINCT CONCAT(user,'''@''',host) AS mysql_user FROM mysql.user;
数据库DATABASE
-- 创建数据库
CREATE DATABASE [IF NOT EXISTS] <数据库名>[[DEFAULT] CHARACTER SET <字符集名>] [[DEFAULT] COLLATE <校对规则名>];
-- 删除数据库
DROP DATABASE [ IF EXISTS ] <数据库名>;
-- 修改数据库
ALTER DATABASE [IF NOT EXISTS] <数据库名>[[DEFAULT] CHARACTER SET <字符集名>] [[DEFAULT] COLLATE <校对规则名>];
-- 查询数据库
SHOW DATABASES;
-- 查看数据库状态
show status;
-- 选择数据库
USE 数据库名;
表TABLE
-- 创建表
CREATE TABLE IF NOT EXISTS 表 (
字段 数据类型 约束 COMMENT '字段备注',
CREATE_DATE DATETIME DEFAULT NULL COMMENT '创建时间',
CREATE_USER int(6) NOT NULL COMMENT '创建用户',
MODIFY_DATE DATETIME DEFAULT NULL COMMENT '修改时间',
MODIFY_USER int(6) NOT NULL COMMENT '修改用户',
STATE char(1) NOT NULL COMMENT '状态',
PRIMARY KEY (字段)
) ENGINE=存储引擎 AUTO_INCREMENT=自增初始值 DEFAULT CHARSET=编码格式;
CREATE TABLE lb_users(
id INT PRIMARY KEY COMMENT '主键',
name VARCHAR(256) NOT NULL COMMENT '用户的真实姓名,不能为空但不用唯一,所以用非空',
user_name VARCHAR(256) UNIQUE COMMENT '用户的姓名,不能为空并且唯一,所以用唯一行校验',
sex CHAR(2) CHECK(sex = '女' OR sex = '男') COMMENT '性别',
marital_status CHAR(2) CHECK(marital_status IN('已婚','未婚')) COMMENT '婚姻状态',
age INT CHECK(age > 0 AND age < 1000) COMMENT '年龄',
height INT CHECK(height between 0 and 500) COMMENT '身高',
password varchar(10) check(length(password)=6) COMMENT '账户密码',
email varchar(10) check (email like '%@%') COMMENT '邮箱',
no varchar(18) check(length(no)=18 and right(no,17)like '[0-9]' or right (no,17) like 'x' ) COMMENT '身份证号码'
)
-- 删除表
drop 表;
-- 改数据类型
ALTER TABLE 表 ADD COLUMN 字段 数据类型;
ALTER TABLE 表 DROP COLUMN 字段;
ALTER TABLE 表 MODIFY COLUMN 字段 数据类型;
-- 改约束
ALTER TABLE 表 ADD CONSTRAINT 字段 约束;
ALTER TABLE 表 ADD CONSTRAINT PRIMARY KEY(字段);
ALTER TABLE temp_b ADD CONSTRAINT CHECK(字段 >< 值 OR/AND ...);
ALTER TABLE 表 DROP CONSTRAINT 字段;
ALTER TABLE 表 MODIFY CONSTRAINT 字段 约束;
------------------ 约束 ------------------
ALTER TABLE 表 MODIFY 字段 CONSTRAINT NN_字段 NOT NULL;
ALTER TABLE 表 ADD CONSTRAINT CK_字段 CHECK (字段= 'A' OR 字段 = 'B' );
ALTER TABLE 表 MODIFY CONSTRAINT DE_字段 字段 DEFAULT 2333;
ALTER TABLE 表 ADD 字段 CONSTRAINT UN_字段 UNIQUE (字段);
ALTER TABLE 表 DROP CONSTRAINT NN_字段;
ALTER TABLE 表 DROP CONSTRAINT CK_字段;
ALTER TABLE 表 DROP CONSTRAINT UK_字段;
ALTER TABLE 表 DROP CONSTRAINT DE_字段;
-- 查看所有表
SHOW TABLES;
-- 显示创表结构
SHOW CREATE TABLE 表;
-- 显示表结构,字段类型,主键,是否为空等属性
DESC 表;
DESCRIBE 表;
备注:
1)每个表必须有这五个字段:state,create_date,create_user,modify_date,modify_user
2)每个实体表必须有对应的历史表
3)表与字段命名规范
字母开头。字母,数字,_,$,#组成。同一用户下表面不能与其他对象同名。
数据类型
类型 | SQL数据类型 | 数据特征 |
枚举 | enum() | enum(‘男‘,‘女‘)。解决mysql的check约束失效。 |
集合 | set() | set(‘男‘,‘女‘)。解决mysql的check约束失效。 |
数值 | TINYINT | 0-255 |
数值 | INT | 0到10位 |
数值 | BIGINT | 0到20位 |
浮点数 | FLOAT | |
浮点数 | DOUBLE | |
浮点数 | NUMBER(N,M) | 小数(精度,小数点后M位) |
浮点数 | DECIMAL | |
时间 | DATE | YYYY-MM-DD |
时间 | TIME | hh:mm:ss |
时间 | DATETIME | YYYY-MM-DD hh:mm:ss |
时间 | TIMESTAMP | YYYY-MM-DD hh:mm:ss 10位或13位时间戳,可应用不同时区 |
定长字符 | CHAR | |
可变长字符 | VARCHAR(m) | 最大字符串长度为m个字节 |
文本 | TEXT | |
大文本 | LONGTEXT | |
图片 | IMAGE | |
二进制 | BIGARY | |
二进制 | VARBIGARY | |
货币 | MONEY | |
货币 | SMALLMINEY |
约束
约束 | 特点 | 例子 | ||
NN | not null | 非空约束 | 非空 | 用户表中没有用户姓名,那么这条记录是没有用的。 |
CK | check | 检查性约束 | 取值约束。 mysql失效,使用enum()或set()字段 | 用户年龄不可能小于0大于200 |
UK | UNIQUE | 唯一约束 | 唯一值或null值 唯一约束在一个表中可以有多个,并且设置唯一约束的列是允许有空值的,虽然只能有一个空值。 | 在用户信息表中,要避免表中的用户名重名,就可以把用户名列设置为唯一约束。 |
DE | default | 默认约束 | 保证字段总会有值,如果没有插入值会有默认值 | 默认值约束通常用在已经设置了非空约束的列,这样能够防止数据表在录入数据时出现错误。 |
PK | primary key | 主建约束 | 唯一性和非空,自动添加索引 | |
FK | FOREIGN KEY(字段) REFERENCES 主表 (字段) | 外键约束 | 外键约束经常和主键约束一起使用,用来确保数据的一致性。 | 一个水果摊只有苹果桃子西瓜 3 种水果,那么你来到水果摊要买水果只能选择苹果桃子和西瓜,不能购买其它的水果。 |
-- 建表时创建
CREATE TABLE 表 (
字段 数据类型 约束 COMMENT '字段备注' PRIMARY KEY (`主键`),
`CREATE_DATE` DATETIME DEFAULT NULL COMMENT '创建时间',
`CREATE_USER` int(6) NOT NULL COMMENT '创建用户',
`MODIFY_DATE` DATETIME DEFAULT NULL COMMENT '修改时间',
`MODIFY_USER` int(6) NOT NULL COMMENT '修改用户',
`STATE` char(1) NOT NULL COMMENT '状态',
UNIQUE KEY `AssetIP` (`AssetIP`)
) ENGINE=[存储引擎] [AUTO_INCREMENT=XX] DEFAULT CHARSET=[编码格式];
-- 建表后创建
ALTER TABLE 表 MODIFY 字段 CONSTRAINT NN_字段 NOT NULL;
ALTER TABLE 表 ADD CONSTRAINT CK_字段 CHECK (字段= 'A' OR 字段 = 'B' );
ALTER TABLE 表 MODIFY CONSTRAINT DE_字段 字段 DEFAULT 2333;
ALTER TABLE 表 ADD 字段 CONSTRAINT UN_字段 UNIQUE (字段);
-- 删除
ALTER TABLE 表 DROP CONSTRAINT NN_字段;
ALTER TABLE 表 DROP CONSTRAINT CK_字段;
ALTER TABLE 表 DROP CONSTRAINT UK_字段;
ALTER TABLE 表 DROP CONSTRAINT DE_字段;
-- 注:
1)创建表先创主表,后创从表。
2)删除表先删从表,后删主表。
3)表添加数据主表先添加从表指向的主键信息,然后从表再添加数据,不然会违反完整约束条件,使其未找到关键字。
存储引擎
数据以什么方式来存储
-- 查看mysql数据库支持的存储引擎
SHOW ENGINES;
-- oracle中不存在存储引擎的概念
存储引擎 | MyISAM | InnoDB |
索引文件 | .MYI | .ibd |
数据文件 | .MYD | .ibd |
事物 | 不支持事务 | 支持事务 |
索引文件与数据文件在一个文件 | 分离/非聚集(叶子节点存储所有索引字段及data地址的指针) | 聚集(叶子节点存储所有索引字段及data数据) |
InnoDB必须有整型的自增主键。 为什么要自增:叶子节点从左至右递增,如果需要添加的索引在其他叶子节点索引大小之间, 需要分裂,平衡等操作,性能开销。 | ||
为什么非主键索引结构的叶子节点存储的是主键值? 一致性和节省存储空间 | ||
回表:如果创建索引的键是其他字段,非主键索引叶子节点存储的是主键值,以此字段作为查询条件的时候,会扫码两遍索引树,先定位主键值,再通过主键值定位到行记录 | ||
索引覆盖:创建索引的键是其他字段,查询的时候,只查询该字段与主键id,通过该字段的索引树就可以获取数据,无需回表 |
序列sequences
-- 设置字段为自增
AUTO_INCREMENT=1
-- 设置自增起始值为1
-- 创建序列
CREATE SEQUENCE 序列名 INCREMENT
BY 数字 --每次增量
MINVALUE 数字 --最小值( noMINVALUE无最小值 )
MAXVALUE 数字 --最大值( noMAXVALUE无最大值 )
START WITH 数字 --初始值
CACHE 数字 NUM --先放 NUM个数据到内存中,但当没取完NUM个数据发生异常时,下次会直接从NUM + 1个开始取。 noCACHE高并发慎用,实例间大量索引块争用。
CYCLE --累加循环( NOCYCLE累加不循环 )。到达最大值后,从最小值重新开始生成序列号。
ORDER;--排序(不排序 noorder)
-- 获取下一个序列值
序列名.nextVal()
索引InnoDB
作用:缩小扫描范围 。提供快速定位到目标数据的有序结构。
索引InnoDB | 特点 | |
普通索引 | INDEX | 基本的索引类型,没有唯一性的限制,允许为NULL值。 |
唯一索引 | UNIQUE INDEX | 数据列不允许重复,允许为NULL,一个表允许多个列创建唯一索引。 |
主键索引 | PRIMARY KEY | 数据列不允许重复,不允许为NULL,一个表只有一个主键。 |
组合索引 | INDEX(字段1,…,字段n) | 最左前缀集合 |
全文索引 | FULLTEXT | 全文索引是对文本的内容进行分词,进行搜索 |
根据叶子节点存储的数据类型分为聚簇索引和非聚簇索引,聚簇索引等同于主键索引,当一个表没有创建主键索引和唯一索引时,innodb会根据rowid字段构建聚簇索引。
- 在表上定义主键PRIMARY KEY,InnoDB将主键索引用作聚簇索引。
- 如果表没有定义主键,InnoDB会选择第一个不为NULL的唯一索引列用作聚簇索引。
- 如果以上两个都没有,InnoDB 会使用一个6 字节长整型的隐式字段 ROWID字段构建聚簇索引。该ROWID字段会在插入新行时自动递增。
-- 主键索引
CREATE index 索引名1,...,索引名n on 数据库表名(字段1,...,字段n) KEYPRIMARY KEY
-- 唯一标识数据库表中的每条记录,每个表可以有多个UNIQUE约束,但是每个表只能有一个PRIMARY约束
UNIQUE KEY
-- 在这个key上建立了一个index
FOREIGN KEY
、、、、
主键 | 外键 | 索引 | |
定义 | 唯一标识一条记录,不能有重复的,不允许为空 | 表的外键是另一表的主键, 外键可以有重复的, 可以是空值 | 该字段没有重复值,但可以有一个空值 |
作用 | 用来保证数据完整性 | 用来和其他表建立联系用的 | 是提高查询排序的速度 |
个数 | 主键只能有一个 | 一个表可以有多个外键 | 一个表可以有多个惟一索引 |
数据结构
数据结构:自平衡二叉树B+Tree+左小右大存放+中序遍历遍历
不用二叉树的原因?
二叉树:右边大于根节点,左边小于根节点。
数据:1,12,23,34,45,56。查找56,得遍历6次,跟直接全部对比的次数一样的,所以此种情形下二叉树存储就没有意义。
不用红黑树的原因?
红黑树:二叉树+左右子树大于两倍则自旋。可以看成弱平衡二叉树。
数据:1,12,23,34,45,56。查找56,得遍历4次。
不用hash 表的原因?
无法进行范围查询与模糊查询
使用B+Tree的原因?
B+Tree:非叶子节点不存储data,只存储索引(冗余的索引);叶子节点存储所有索引字段及data,用指针连接提高范围查找性能。
数据:1,12,23,34,45,56。查找56,得遍历3次。
非叶子节点mysql默认16KB。高度为3时叶子节点就可存储千万级别的数据量。
--查询数据库设置的节点大小
SHOW GLOBAL STATUS LIKE "innodb_page_size%"
- 一个节点即一页的大小为16k(如果用bigint作为索引,8个字节+6字节的下一个页的物理地址,也就是每个节点大概可以存储1600个索引数据,第二次就可以存储1100*1100=1,210,000个索引数据,第三层如果为叶子节点假设一条数据1kb那么一页可以存储16条数据,三层结构总共大概可以存储千万条数据)
- 非叶子节点只存储索引数据(只存储索引数据可以增加节点分叉,降低树的高度,较少磁盘的io次数)
- 聚簇索引中叶子节点存储整行的数据,非聚簇索引存储主键索引的地址。
- 叶子节点之间有前后指针,因为mysql需要提供范围查询的功能,该指针可以提供快速查询范围结果的效率
使用索引
一本汉语字典中有上万个字,要想查找某个字
第一种方式:一个字一个字的查找
第二种方式:先去目录找a,b,c,d…,然后根据下标翻到对应页数查找。
mysql查询也是一样,有两种方式进行查询
1:全表扫描
2:根据索引检索
此时可以发现字典目录abcd也是有排序的,为什么要排序呢?因为可以区间查找缩小寻找范围(mysql缩小扫描范围只扫描某个区间)。
主键 | 外键 | 索引 | |
定义 | 唯一标识一条记录,不能有重复的,不允许为空,自动有索引 | 表的外键是另一表的主键, 外键可以有重复的, 可以是空值 | 该字段没有重复值,但可以有一个空值 |
作用 | 用来保证数据完整性 | 用来和其他表建立联系用的 | 是提高查询排序的速度 |
个数 | 主键只能有一个 | 一个表可以有多个外键 | 一个表可以有多个惟一索引 |
什么时候给字段添加索引
1:数据量庞大。
2:该字段经常作为查询条件存在。
3:该字段很少进行DML操作(增删改),因为在DML之后,索引需要重新排序。
4:字段数据的唯一性高,没有大量的重复数据。
因为索引是需要维护的,所有不要随便添加索引,建议通过主键,unique进行查询。
-- 创建索引
CREATE INDEX 索引名 1,...,索引名 n ON 数据库表名 (字段 1,...,字段 n )
-- 复合/联合索引
CREATE INDEX 索引名 ON 数据库表名 (字段 1,...,字段 n ) CREATE TABLE 表 (
INDEX (字段名),
-- 普通索引。可有多个,允许为null。
UNIQUE INDEX (字段名),
-- 唯一索引。可有多个,允许为null。
KEY(字段名)
-- 普通索引
PRIMARY KEY(字段名)
-- 主键索引,每张表只能有一个主键索引。
UNIQUE KEY(字段名)
-- 唯一索引,每张表可以有多个唯一索引。
FOREIGN KEY(字段名)
-- 外键。相当于在这个key上建立了一个index。
)
-- 查看表是否建立索引
SHOW KEYS FROM 表名;
-- 开启表中的索引开启:
ALTER TABLE 表名 ENABLE KEYS;
-- 关闭表中的索引开启:
ALTER TABLE 表名 DISABLE KEYS ;
-- 删除索引
DROP index 索引名1,...,索引名n on 数据库表名
-- 查看sql语句是否使用索引进行查询
explain select语句
-- type为all表示没有索引,为ref表示有索引
索引失效
1:查询条件使用模糊查询以%开始
select * from 数据库表名 where 字段 like '%XXX'; --无索引
2:条件是or关系,并且某个字段没带索引(解决方案:使用union)
-- 字段2没有索引
select * from 数据库表名 where 字段1=XXX or 字段2=YYY; --无索引
3:数据类型隐形转换
-- 字段是字符串类型
select * from 数据库表名 where 字段='XXX'; --有索引select * from 数据库表名 where 字段=XXX; --无索引
4:数学运算
select * from 数据库表名 where 字段+Y=XXX; --无索引
5:对有索引的字段使用函数
select * from 数据库表名 where 函数(字段)=XXX; --无索引
6:使用复合索引的时候,没有使用左侧的字段查找
CREATE index 索引名 on 数据库表名(字段1,...,字段n) select * from 数据库表名 where 字段1=XXX; --有索引select * from 数据库表名 where 字段n=XXX; --无索引
7:使用混合排序(DESC与ASC 都存在)。where条件列与order by列不一样。
索引分类
聚集索引 :带有主键的表
查询变快 。
写入、修改、删除变慢 。因为平衡树这个结构必须一直维持在一个正确的状态, 增删改数据都会改变平衡树各节点中的索引数据内容,破坏树结构, 因此,在每次数据改变时, DBMS必须去重新梳理树的结构以确保它的正确 。
非聚集索引:索引
索引分为三大类:唯一索引、主键索引和聚集索引。
优点
第一,加快数据的检索速度。
第二,创建唯一性索引,保证数据库表中每一行数据的唯一性。
第三,在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间。
缺点
第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
第二,索引需要占物理空间。
第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
索引 | |
单一索引 | 一个字段上添加一个索引 |
复合索引 | 多个字段上添加同一个索引 |
主键索引 | 主键 |
唯一索引 | unique |
唯一索引与主键索引 | 唯一索引 | 主键索引 |
1、主键一定是唯一性索引,唯一性索引并不一定就是主键。 | ||
2、一个表中可以有多个唯一索引,但只能有一个主键。 | ||
3、主键列不允许空值null,而唯一性索引列允许空值null。 |
主键索引与聚集索引 | 主键索引 | 聚集索引 |
用途 | 强制表的实体完整性 | 对数据行的排序,方便查询用 |
一个表多少个 | 一个表最多一个主键 | 一个表最多一个聚集索引 |
是否允许多个字段来定义 | 一个主键可以多个字段来定义 | 一个索引可以多个字段来定义 |
是否允许 null 数据行出现 | 如果要创建的数据列中数据存在null,无法建立主键。 创建表时指定的 PRIMARY KEY 约束列隐式转换为 NOT NULL。 | 没有限制建立聚集索引的列一定必须 not null . 也就是可以列的数据是 null 参看最后一项比较 |
是否要求数据必须唯一 | 要求数据必须唯一 | 数据即可以唯一,也可以不唯一。看你定义这个索引的 UNIQUE 设置。 (这一点需要看后面的一个比较,虽然你的数据列可能不唯一,但是系统会替你产生一个你看不到的唯一列) |
创建的逻辑 | 数据库在创建主键同时,会自动建立一个唯一索引。 如果这个表之前没有聚集索引,同时建立主键时候没有强制指定使用非聚集索引,则建立主键时候,同时建立一个唯一的聚集索引 | 如果未使用 UNIQUE 属性创建聚集索引,数据库引擎 将向表自动添加一个四字节 uniqueifier 列。 必要时,数据库引擎 将向行自动添加一个 uniqueifier 值,使每个键唯一。此列和列值供内部使用,用户不能查看或访问。 |
--索引树:占存储空间。加速数据存取(类似树,树的节点存储的是每条记录的物理地址-伪列)
CREATE INDEX 索引树 ON 表(列,...,列) REVERSE;
--防止某个字段的值为连续增长的值,形成歪脖子树,增加查询的层次,性能下降,可使索引值变得不规则,使索引树能均匀分布。
虚拟表(视图或伪列)
虚拟表,来自一个或多个真实表中的字段组合而成的虚拟表。只可查询,不可增删改。
-- 视图:不占存储空间
CREATE VIEW 视图 AS SELECT语句;
-- 临时表:一行一列,做数据运算。
-- (多表合成一张表,查询语句之间用UNION或UNION ALL连接),其中UNION会连接后去重,UNION ALL不会去重。例如:select * from 表一 UNION或UNION ALL select * from 表二
CREATE TEMPORARY TABLE 临时表名 查询语句;
-- 伪列:像表中的列,但没有存储在表中,可查不可增删改ROWNUM 分页查询
CREATE VIRTUAL TABLECREATE TABLE dualROWID
优点
1)简单性。视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使用户不必为以后的操作每次都指定全部的条件。
2)安全性。通过视图用户只能查询和修改他们所能见到的数据。数据库中的其他数据则既看不见也取不到。数据库授权命令可以使每个用户对数据库的检索限制到特定的数据库对象上,但不能授权到数据库特定行和特定的列上。通过视图,用户可以被限制在数据的不同子集上。
3)逻辑数据独立性。视图可以使应用程序和数据库表在一定程度上独立。如果没有视图,应用一定是建立在表上的。有了视图之后,程序可以建立在视图之上,从而程序与数据库表被视图分割开来。
缺点
1)性能:SQL Server必须把视图的查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,SQL Server也把它变成一个复杂的结合体,需要花费一定的时间。
2)修改限制:当用户试图修改视图的某些行时,SQL Server必须把它转化为对基本表的某些行的修改。对于简单视图来说,这是很方便的,但是,对于比较复杂的视图,可能是不可修改的。
数据操纵DML (表中数据)
英文全称:Data Manipulation Language
INSERT增
INSERT INTO 表(字段名) VALUES(值);
注:
1)INSERT INTO必须指明插入字段,哪怕是全表插入。
DELETE删
UPDATE改
UPDATE 表 SET 列 = 新值 WHERE 条件;
SELECT查
(7)SELECT 字段 as 别名
(8)DISTINCT 去重
UNION 合并多个结果集
INTO 创建新表并将查询内容插入新表中
字段a+字段b
如果两个字段都为数值,则求和;例如1+2为3
如果一个为字符型,另一个为数值型,则会试图把字符型转为数值型,字符型转换成功则求和。例如'1'+2 为3
如果一个为字符型,另一个为数值型,则会试图把字符型转为数值型,字符型转换失败则置0。例如'liubo'+2 为2
如果有一个为null,则结果为null。
CONCAT 拼接字段值,当有一个字段值为null时,拼接结果直接为null(可以用IFNULL做判断)。
(1)FROM 表 别名
(3)<join_type> JOIN <right_table>
(2)ON 条件
连接查询条件
(4)WHERE 条件
条件
(5)GROUP BY 字段
分组字段(除分组函数外的其他字段)
(6)HAVING 条件
中间结果集查询筛选
(9)ORDER BY 字段 ASC/DESC
排序
(10)LIMIT 0,100;
1、FORM: 对FROM左边的表和右边的表计算笛卡尔积,产生虚表VT1。
2、ON: 对虚表VT1进行ON过滤,只有那些符合<连接查询条件>的行才会被记录在虚表VT2中。
3、JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3。
4、WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合<条件>的记录才会被插入到虚拟表VT4中。
5、GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5。
6、HAVING: 对虚拟表VT5应用having过滤,只有符合<中间结果集查询筛选>的记录才会被 插入到虚拟表VT6中。
7、SELECT: 执行select操作,选择指定的列,插入到虚拟表VT7中。
8、DISTINCT: 对VT7中的记录进行去重。产生虚拟表VT8.
9、ORDER BY: 将虚拟表VT8中的记录按照<排序,默认升序>进行排序操作,产生虚拟表VT9.
10、LIMIT:取出指定行的记录,产生虚拟表VT10, 并将结果返回。
注:
1)on与where的区别
on是生成临时表时使用的条件,无论真假都返回左表数据。
where在生成临时表之后使用的条件,返回满足条件的记录。
2)LIMIT的几种写法
LIMIT [offset, ]rows
LIMIT rows OFFSET offset
举例:
LIMIT 0,5 【0+1,0+5】
LIMIT 0,-1 【0+1,+∞)
LIMIT 5 【0~5】
LIMIT 5 OFFSET 0 【0+1,0+5】
偏移量小,使用LIMIT。偏移量大,使用OFFSET。
一.连接查询(多表查询)
1)交叉连接查询。这种查询方式得到的是两个表的乘积(笛卡儿集)
SELECT * FROM t_a,t_b WHERE aid=bid;
2)内连接:两个表的交集
等值内连接
SELECT * FROM t_a a,t_b b WHERE a.aid=b.bid; -- 隐式
SELECT * FROM t_a a JOIN t_b b on a.aid=b.bid; -- 显式
非等值内连接
SELECT * FROM t_a a,t_b b WHERE a.aid between b.value1 and b.value2;-- 隐式
SELECT * FROM t_a a JOIN t_b b on a.aid between b.value1 and b.value2;-- 显式
自连接
SELECT * FROM t_a a,t_a b WHERE a.aid=b.aid;-- 隐式
SELECT * FROM t_a a JOIN t_a b on a.aid=b.aid;-- 显式
3)外连接
左外连接
SELECT * FROM t_a LEFT JOIN t_b ON aid=bid;
右外连接
SELECT * FROM t_a RIGHT JOIN t_b ON aid=bid;
二.子查询:搜索条件在另外的表中
SELECT * FROM t_a WHERE aid IN(SELECT bid FROM t_b)
三.联合查询
UNION 合并多个结果集,联合查询条件:结果字段数相等
注:
1)多表必须使用别名,字段必须通过别名调取。
2)Oracle相同ID有多条记录,取时间最近的一条
-- Oracle相同ID有多条记录,取时间最近的一条
select *
from (select t.*,
row_number() over(partition by t.strcaseid order by t.cu_date desc) rn
from b_push t) c
where rn = 1;
运算符
比较运算符 | 用途 |
LIKE | 模糊查询 。%代表匹配任意个任意字符;-代表匹配单个任意字符;转义用\,也可以通过ESCAPE去设置转义字符。 |
BETWEEN 值1 AND 值2 | 字段在值1与值2之间。[值1,值2] |
IN() | 字段值是否属于in列表中的某一项 |
IS NULL | 字段是否为空 |
AND | 与 |
OR | 或 |
NOT | 非 |
:= | 赋值 |
… | 范围 |
|| | 字符串连接 |
常用函数
函数 | 用途 |
EXISTS | 是否存在 |
EXISTS(查询语句) | 当查询到数据时,则返回true,否则为false。 |
UNION | 合并两个或多个 SELECT 语句的结果集并去重。 |
UNION ALL | 合并两个或多个 SELECT 语句的结果集。 |
LIMIT m,n | 从m+1行开始取,取n行 |
字符串函数
函数 | 用途 |
IFNULL(expr1,expr2) | 如果expr1不是NULL,则返回expr1,否则返回expr2。 |
concat(str1, str2, …) | 连接字符串,如果有任何一个参数为null,则返回值为null。 |
concat_ws(separator, str1, str2, …) | 指定连接符连接字符串,如果有任何一个参数为null,则返回值为null。 |
group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator] ) | 将group by产生的同一个分组中的值连接起来,返回一个字符串结果。 |
CHARINDX() | |
LENGTH | 字符串的字节长度 |
UPPER | 转为大写 |
LOWER | 转为小写 |
SUBSTR(a,m,n) | 截取字符串a,从m开始,截取n个。 |
INSTR(字符串,子串) | 返回子串第一次出现的索引; 如果没有找到就返回0 |
TRIM(字符串) | 去除前后空格。如果想去除前后某个字符,可以写成TRIM(字符 from 字符串) |
LPAD(字符串,填充长度,字符) | 用指定字符实现左填充指定长度。如果填充长度小于字符串长度,将截取字符串。 |
RPAD(字符串,填充长度,字符) | 用指定字符实现右填充指定长度。如果填充长度小于字符串长度,将截取字符串。 |
REPLACE(字符串,字符1,字符2) | 将字符串中的字符1替换成字符2 |
LOCATE(substr,str) | 返回字符串substr中第一次出现子字符串的位置 str。 |
GROUP_CONCAT([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段][Separator ‘分隔符’]) | |
STRCMP(expr1,expr2) | 如果字符串相同,STRCMP()返回0,如果第一参数根据当前的排序次序小于第二个,返回-1,否则返回1。 |
FIND_IN_SET(str,strlist) | 假如字符串str 在由N个子链组成的字符串列表strlist 中,则返回值的范围在 1 到 N 之间,如果没有的话返回0。 |
ascll(x) | 返回x的ascii码 |
dbms_output.put_line() | 日志输出 |
数字函数
数字函数 | 用途 |
ROUND(x,y) | x在y的位置四舍五入取整 |
CEIL() | 向上取整 |
FLOOR() | 向下取整 |
TRUNCATE(x,y) | x直接截断到小数点后y位 |
MOD(a,b) | 取余。相当于%,a%b=a-a/b*b |
FORMAT(x,n) | 函数可以将数字x进行格式化,将x保留到小数点后n位。这个过程需要进行四舍五入 |
POWER(m,n) | m的n次幂 |
ABS() | 取绝对值 |
SQRT(n) | 根号n |
INTERVAL(6,1,2,3,4,5,6,7,8,9,1) | 返回比N大的位置 |
日期函数
日期函数 | 用途 |
sysdate | 获取系统时间 |
add_months(month,n) | 在month当前月上增加n个月 |
lase_day(month) | month月份的最后一天 |
months_between(date1,date2) | date1与date2之间的月份 |
nex_day(date,weekday) | date下个星期weekday的时间 |
NOW()或GETDATE() | 获取当前时间。2008-08-08 08:08:08 |
CURDATE()或CURRENT_DATE或CURRENT_DATE() | 获取当前时间。2008-08-08 |
CURTIME()或CURRENT_TIME或CURRENT_TIME() | 获取当前时间。08:08:08 |
FROM_UNIXTIME | 数字时间戳 转换成 字符串时间 |
UNIX_TIMESTAMP(“YYYY-MM-DD hh:mm:ss”) | 字符串时间 转换成 数字时间戳 |
DATEDIFF(date1,date2) | 返回两个日期之间的天数。DATEDIFF(‘2008-12-29’,‘2008-12-30’) |
DATEDIFF(datepart,startdate,enddate) | 返回两个日期之间的时间,datepart参数 |
转换函数
转换函数 | 用途 |
TO_CHAR(A,B) | 把A转换为B格式的字符串 A:日期或数字 B:格式化的字符串"yyyyMMddhhmmss" |
TO_DATE(A,B) | 把A转换为B格式的日期 A:字符串 B:格式化字符串 |
TO_NUMBER(A,B) | 把A转换为B格式的数字 A:字符串 B:格式化字符串 |
INET_ATON | 字符串的网络地址,返回一个代表地址数值的整数 |
INET_NTOA | 给定一个数字网络地址,返回作为字符串的该地址的电地址表示 |
聚合函数
聚合函数 | 用途 |
NVL(x,y) | 如果x为空,则返回y |
NVLZ(x,y,z) | 如果x为空,则返回z,否则返回y |
SUM() | 求和。忽略NULL值 |
COUNT() | 计数。忽略NULL值 |
MAX() | 最大值。忽略NULL值 |
MIN() | 最小值。忽略NULL值 |
AVG() | 平均值。忽略NULL值 |
流程控制-判断
IF
IF search_condition THEN statement_list;
ELSEIF search_condition THEN statement_list;
ELSEIF search_condition THEN statement_list;
ELSE statement_list;
END IF;
-- 相当于三目运算符
IF(expr1,expr2,expr3)
CASE 参数
WHEN '值1' THEN 结果1;
WHEN '值2' THEN 结果2;
ELSE 结果n
END;
-- 相当于if-else
IF 表达式 THENELSEEND IF;
WHEN 条件 THEN 结果;
CASE
-- 语法一(相当于switch):
CASE case_value
WHEN when_value THEN statement_list
WHEN when_value THEN statement_list
ELSE statement_list
END CASE
-- 语法二:
CASE
WHEN search_condition THEN statement_list
WHEN search_condition THEN statement_list
ELSE statement_list
END CASE
流程控制-循环
退出循环 | LEAVE xxx | ITERATE xxx |
特点 | 退出 | 跳过此次循环开始下一次循环 |
类似java中的 | break | continue |
loop
loop是死循环,需要手动退出循环。
-- loop循环
LOOP
-- sql
-- 退出循环方式1
IF 表达式 THEN
exit;
END IF;
-- 退出循环方式2
WXIT WHEN 表达式;
END LOOP;
-- WHILE循环
WHILE 参数 DO
END WHILE;
-- FOR循环
FOR 参数 IN XX ... ZZ LOOP
END LOOP;
-- FETCH循环
FETCH 参数 INTO 变量1,...,变量N
-- sql
-- 退出循环
WXIT WHEN 表达式;
END LOOP;
while
类似java的while(){}。
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
repeat
[begin_label:] REPEAT
statement_list
UNTIL search_condition -- 直到…为止,才退出循环
END REPEAT [end_label]
数据控制DCL
英文全称:Data Control Language
GRANT授予权限
REVOKE回收权限
COMMIT提交事务
ROLLBACK回滚事务
角色
权限---->用户
变为
权限---->角色---->用户
-- 把角色给用户
grant 角色 to 用户名
权限
-- 查询权限
select * from system_privilege_map;
系统权限
用户使用数据库的权限(对用户而言)
系统权限 | 特点 | 可授予用户 |
dba | 最高权限,只有dba才可以创建数据库结构 | dba管理员 |
resource | 只可以创建实体,不可创建数据库结构 | dba管理员 普通用户 |
connect | 只可以登录oracle,不可用创建实体与数据库结构 | dba管理员 普通用户 |
系统权限只能有dba用户授权,即最开始的两个用户是sys,system,普通用户提供授权也可以具有system相同的权限,但是无法达到与sys相同的权限,system的权限也能被回收。
-- 系统权限传递
grant XXX to 用户名 whit admin option;
-- 系统权限回收(只能有dba用户回收)
revoke XXX from 用户名
-- 系统权限回收无级联,也可以跨用户回收
实体权限
对象A授予给对象B,去访问A成员的权限(对表,视图,索引而言),即某种权限用户对其他用户的表或视图存取的权限。
权限 | 表 | 视图 | |
select | 选择 | √ | √ |
update | 更新 | √ | √ |
insert | 插入 | √ | √ |
alter | 修改 | √ | √ |
index | 索引 | √ | × |
delete | 删除 | √ | √ |
execute | 执行 | √ | × |
references | 关联 | √ | √ |
all | 所有权限 | √ | √ |
-- 实体权限传递
grant XXX to 用户名 whit grant option;
-- 实体权限回收
revoke XXX from 用户名
-- 实体权限回收有级联,当回收权限时,传递的权限将全部失去。
事务控制TCL
英文全称:Transaction Control Language
事务 Transaction
一个或者一组sql语句组成的一个执行单元,这个执行单元要么全部执行,要么全部不执行。这个执行单元是一个不可分割的整体。 如果单元中某一条sql语句执行失败,整个执行单元将回滚(所有受影响的数据将返回到事务开始之前的状态)。如果单元中的sql语句都顺利执行,则事务将顺利执行。
例如:张三给李四转500块钱,sql语句编写的话,首先张三减少500,然后李四增加500元,这两条sql语句要么全部执行,要么全部不执行,这样子才能保障钱的总数是正确的。
----------------------------- MySQL中对事务操作的支持 -----------------------------
-- 开启一个事务
start transaction;
-- 成功就提交事务
commit;
-- 失败就回滚事务
rollback;
----------------------------- JDBC中事务操作代码 -----------------------------
con.setAutoCommite(false);
con.commit();
con.rolllback();
----------------------------- MySQL中对事务隔离级别的支持 -----------------------------
-- 查看当前级别
select @@tx_isolation;
-- 设置隔离级别,要在开启事务之前设置
set session(blobal) transaction isolation level 级别;
-- 设置当前回话的隔离级别
session
-- 设置全局的隔离级别
global
-- JDBC中事务隔离级别操作代码
con.setTransactionIsolation(隔离级别设置);
四大特征ACID
原子性(Atomicity):事务是一个不可分割的工作单位,事务的操作要么全部执行,要么全部不执行。
一致性(Consistency):事务必须使数据库从一个一致性状态变换到另一个一致性状态。即事务执行失败,就将对前面的操作进行回滚。
隔离性(Isolation):一个事务的执行不受其它事务的影响。
同时运行多个事务,当这些事务访问数据库中相同的数据,如果没有采取必要的隔离机制,会导致以下三种并发问题。
并发问题 | 现象 | 产生场景 | 解决方案 |
脏读 | 两个事务T1,T2。T1读取了已经被T2更新但还没有提交的字段,如果T2回滚,T1读取的数据将是临时无效的。 | 读写 | MVCC |
不可重复读 | 两个事务T1,T2。T1与T2读取了同一个字段,然后T2更新该字段,当T1再次读取该字段时,值就有可能不一样了。 | 读写 | MVCC |
幻读 | 两个事务T1,T2。T1从表中读取了字段,T2在该表增删数据,如果T1再次读取表,将会多或少几行。 | 增删 | Next-Key Lock行锁+间隙锁 |
三种并发问题采取的隔离机制。
隔离级别 | 避免脏读 | 避免不可重复读 | 避免幻读 |
Read uncommitted (读未提交) | √ | √ | √ |
Read committed (读已提交) | × | √ | √ |
Repeatable read (可重复读) | × | × | √ |
Serializable (串行化) | × | × | × |
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当级别越高执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。
在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
持久性(Durability):事务一旦被提交,则会对数据库中的数据永久性改变。
事务的创建
隐式事务:事务没有明显的开启与结束的标记。比如insert,update,delete语句,也是一个事务。但是这种事务是自动提交的。
显式事务:设置自动提交功能为禁用。
-- 设置自动提交功能为禁用。
SET autocommit=0;
-- 开启事务
start transaction;
-- sql语句(select,insert,update,delete这四种DML语言)
savepoint 回滚节点名;
--一个事务中可以有多个
SAVEPOINT RELEASE SAVEPOINT 回滚节点名;
--一个删除事务commit;/rollback;
-- 成功就提交事务或失败就回滚事务,二选一。
commit提交之后即可改变底层数据库数据
-- 回滚
rollback to 回滚节点名;
MVCC 事务隔离的实现
Multi-Version Concurrency Control 多版本并发控制
作用:不加锁实现多事务的并发读-写
维持一个表数据的多个版本,使得读-写操作没有冲突,抛弃以往解决读-写冲突采用悲观锁,MVCC 是无锁并发控制
当前读 | 它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁 |
快照读 | 快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读; 快照读的实现是基于MVCC多版本并发控制,快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本 |
并发场景 | 存在的问题 | 解决方案 |
读-读 | 不存在任何问题,也不需要并发控制 | |
读-写 | 有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读 | MVCC |
写-写 | 有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失 | 乐观锁/悲观锁 |
利用版本链以及对应的undo日志,通过快照读取的方法来控制各个级别的事务所能够读取到的信息。
MVCC | 能否解决 |
脏读 | 能 |
不可重复读 | 能 |
幻读 | 不能 |
隔离级别 | 使用MVCC | 生成 |
Read uncommitted (读未提交) | 不使用 每次查询都取最新的记录即可 | |
Read committed (读已提交) | 使用 | 每一次进行普通 |
Repeatable read (可重复读) | 使用 | 只在第一次进行普通 |
Serializable (串行化) | 不使用 |
实现原理
MVCC = 版本链 + read-view
版本链:
在InnoDB的表中必须包含两个字段,trx_id
(事务id)和roll_pointer
(回滚指针)。
每当事务操作都会生成一条undo log日志,回滚指针指向前一条记录,随着更新的次数增多,数据会逐渐被连接成一个链,也就是所说的版本链。
read-view =[所有未提交事务id数组],已创建的最大事务id
已创建=未提交事务+已提交事务
版本链对比read-view数组的规则
update+select情况
1:如果trx_id < min_id,则落在青色部分,表示这个版本是由已提交事务生成的,这个数据是可见的
2:如果trx_id > max_id,则落在棕色部分,表示这个版本是由将来启动的事务生成的,这个数据是不可见的
3:如果min_id <= trx_id <= max_id,则落在黄色部分,又分为两种情况:
a:如果row的trx_id在数组中,表明这个这个版本是由未提交事务生成的,这个数据是不可见的
b:如果row的trx_id不在数组中,表明这个这个版本是由已提交事务生成的,这个数据是可见的
delete+select情况
1:将版本链上的最新数据复制一份,然后将trx_id修改成删除操作的trx_id,同时在该条记录的record header头信息里的delete_flag标志位改为true,表示当前记录已经被删除。
2:查询的时候按照update+select情况下的规则走一遍,
最后查询一下delete_flag,如果标志位为true,表示记录已经被删除,不返还数据。
隐式字段
每行数据除了自定义的字段外,还有数据库隐式定义的字段。
隐式字段 | 用途 | 字节大小 |
DB_TRX_ID | 最近修改( | 6byte |
DB_ROLL_PTR | 回滚指针,指向这条记录的上一个版本(存储于rollback segment里) | 7byte |
DB_ROW_ID | 隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以 | 6byte |
undo 回滚日志
undo日志 | |
insert undo log | 代表事务在 |
update undo log | 事务在进行 |
Read View 一致性视图
事务进行快照读操作的时候生产的读视图。
事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大)
当我们某个事务执行快照读的时候,对该记录创建一个Read View
读视图,把它比作条件用来判断当前事务能够看到哪个版本的数据,既可能是当前最新的数据,也有可能是该行记录的undo log
里面的某个版本的数据。
可见性算法,主要是将要被修改的数据的最新记录中的DB_TRX_ID(即当前事务ID)取出来,与系统当前其他活跃事务的ID去对比(由Read View维护),如果DB_TRX_ID跟Read View的属性做了某些比较,不符合可见性,那就通过DB_ROLL_PTR回滚指针去取出Undo Log中的DB_TRX_ID再比较,即遍历链表的DB_TRX_ID(从链首到链尾,即从最近的一次修改查起),直到找到满足特定条件的DB_TRX_ID, 那么这个DB_TRX_ID所在的旧记录就是当前事务能看见的最新老版本
SQL优化
一)查看SQL执行频率
show status
-- 增删改错sql的执行次数
show global status like 'Com_______'
二)定位慢查询SQL
日志定位
-- 查看慢查询日志。具体字段如下表
show variables like '%slow_query_log%';
-- 开启慢查询日志
set global slow_query_log=1;
-- 设置慢查询的超时时间(秒)
set global long_query_time=2;
-- 注意: 使用set global slow_query_log=1开启了慢查询日志只对当前数据库生效,MySQL重启后则会失效。如果要永久生效,就必须修改配置文件my.cnf
Variable_name | Value |
slow_query_log | 是否启动了慢查询日志。ON代表启动,OFF表示禁用 |
slow_query_log_file | 慢查询日志日志 |
-- 查看profile是否可用。查询结果为1代表可用
SELECT @@profiling;
-- 开启profile。profile是用户级变量,每次都得重新启用
SET profiling = 1;
-- 查看当前会话下的所有sql执行时间
show profiles;
-- 查看具体sql的每个步骤消耗时间及cpu消耗时间
show profile cpu for query xx-Query_ID;
Query_ID | Duration | Query |
查询id | 持续时间 | Sql |
explain分析
表的读取顺序
数据读取操作的操作类型
哪些索引可以使用
哪些索引被实际使用
表之间的引用
每张表有多少行被优化器查询
explain sql语句;
id | 查询序列号 | 每一个id代表一个select,不同的id代表不同的子查询。 id越大优先级越高,越先被解析; id相同则从上往下执行; id为NULL最后执行 |
select_type | 查询的类型 | (1) SIMPLE(简单SELECT,不使用UNION或子查询等) (2) PRIMARY(子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY) (3) UNION(UNION中的第二个或后面的SELECT语句) (4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询) (5) UNION RESULT(UNION的结果,union语句中第二个select开始后面所有select) (6) SUBQUERY(子查询中的第一个SELECT,结果不依赖于外部查询) (7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,依赖于外部查询) (8) DERIVED(派生表的SELECT, FROM子句的子查询) (9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行) |
table | 输出结果集的表 | 数据来源于哪张表 |
partitions | 分区表 | 访问的分区 |
type | 表的连接类型 | 常用的类型有: ALL、index、range、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好) ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行 index: Full Index Scan,index与ALL区别为index类型只遍历索引树 range:只检索给定范围的行,使用一个索引来选择行 ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值 eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件 const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。 |
possible_keys | 可能走的索引 | |
key | 实际使用的索引 | |
key_len | 索引字段的长度 | 表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的) 不损失精确性的情况下,长度越短越好 |
ref | 列与索引的比较 | 索引关联查询的字段,也有可能是常量值 |
rows | 要扫描的行数 | 估计要扫描的行数,不是准确的值 |
filtered | 过滤列表示根据表条件过滤的表行的估计百分比。 | 过滤列表示根据表条件过滤的表行的估计百分比。最大值为100,这意味着没有对行进行过滤。值从100下降表示过滤量增加。Rows显示检查的行数,Rows × filtered显示与下表连接的行数。例如,如果rows为1000,filtered为50.00(50%),则与下表join的行数为1000 × 50% = 500。 |
Extra | 额外信息 | 该列包含MySQL解决查询的详细信息,有以下几种情况: Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤 Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by ; order by Using filesort:当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序” – 测试Extra的filesort explain select * from emp order by name; Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。 Impossible where:这个值强调了where语句会导致没有符合条件的行(通过收集统计信息不可能存在结果)。 Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行 No tables used:Query语句中使用from dual 或不含任何from子句 – explain select now() from dual; |
三)优化
数据库优化维度有四个:
硬件、系统配置、数据库表结构、SQL及索引。
查询 | 索引失效 |
字段 like “%xxx” | 模糊查询%开始 |
字段 = 1 or 字段2 = 2 | 字段没带索引 |
数据类型隐形转换 | |
字段*2=36 | 数学运算 |
对有索引的字段使用函数 | |
使用复合索引的时候,没有使用左侧的字段查找 | |
1:查询条件使用模糊查询以%开始
2:多条件是or关系,并且某个字段没带索引(解决方案:使用union)
3:数据类型隐形转换
4:数学运算
5:对有索引的字段使用函数
6:使用复合索引的时候,没有使用左侧的字段查找
### 多机优化
主要解决IO瓶颈问题:
读写分离:做集群,让多台服务器提供服务。
分布式:把不同的业务分给不同的集群处理。
### 缓存
redis
1. 查看优化器状态
- show variables like 'optimizer_trace';
2. 会话级别临时开启
- set session optimizer_trace="enabled=on",end_markers_in_json=on;
3. 设置优化器追踪的内存大小
- set OPTIMIZER_TRACE_MAX_MEM_SIZE=1000000;
4. 执行自己的SQL
- select host,user,plugin from user;
5. information_schema.optimizer_trace表
- SELECT trace FROM information_schema.OPTIMIZER_TRACE;
6. 导入到一个命名为xx.trace的文件,然后用JSON阅读器来查看(如果没有控制台权限,或直接交由运维,让他把该 trace 文件,输出给你就行了。 )。
- `SELECT TRACE INTO DUMPFILE "E:\\test.trace" FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;`
**注意:不设置优化器最大容量的话,可能会导致优化器返回的结果不全。**
SQL优化
分页查询优化
join关联优化
order by和group by
1.创建索引:创建合适的索引,我们就可以在索引中查询,查询到以后直接找对应的额记录
2,分表:当一张表的数据比较多或者一张表的某些字段的值比较多并且很少使用时,采用水平分表或垂直分表来优化,比如spu表
3,读写分离:当一台服务器不能满足需要时,采用将读写分离的方式进行集群
表结构
(表结构、索引、sql语句本身问题)
表结构的创建:结合业务情况,合理运用 3NF和反3NF以及选择合适的存储引擎。
索引:创建可以最大程度的提升系统效率的索引。
分表:合理运用垂直分表和水平分表,提高查询效率。
分区 以及sql优化技巧。
DDL优化:
1. 通过禁用索引来提供导入数据性能,这个操作主要针对有数据的表追加数据
2. 关闭唯一校验
3. 修改事务提交方式(导入)(变多次提交为一次)
DML优化: 把多条插入的语句合并为一条(变多次提交为一次)
DQL优化:
Order by 优化
多用索引排序
普通结果排序(非索引排序)
Group by 优化:如果对排序的结果没有排序的需求,可以考虑在其后面加上order by nul
子查询优化
Or优化:
1.or两边都是用索引字段做判读,性能好
2.or两边,有一边不用,性能差
3.如果name=”a” or name=”b”,这种方式,索引失效
Limit优化
《阿里巴巴JAVA开发手册》里面写超过三张表禁止join 这是为什么?
需要 join 的字段,数据类型必须绝对一致;多表关联查询时, 保证被关联的字段需要有索引。 说明:即使双表 join 也要注意表索引、SQL 性能
这样的话那sql要怎么写?
1、对查询进行优化,应尽量避免全表扫描,首先应考虑在 WHERE 及 ORDER BY 涉及的列上建立索引。
2、应尽量避免在 WHERE 子句中对字段进行 NULL 值判断,创建表时 NULL 是默认值,但大多数时候应该使用 NOT NULL,或者使用一个特殊的值,如 0,-1 作为默认值。
3、应尽量避免在 WHERE 子句中使用 != 或 <> 操作符。MySQL 只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的 LIKE。
4、应尽量避免在 WHERE 子句中使用 OR 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,可以使用 UNION 合并查询:select id from t where num=10 union all select id from t where num=20。
5、IN 和 NOT IN 也要慎用,否则会导致全表扫描。对于连续的数值,能用 BETWEEN 就不要用 IN:select id from t where num between 1 and 3。
6、下面的查询也将导致全表扫描:select id from t where name like‘%abc%’ 或者select id from t where name like‘%abc’若要提高效率,可以考虑全文检索。而select id from t where name like‘abc%’才用到索引。
7、如果在 WHERE 子句中使用参数,也会导致全表扫描。
8、应尽量避免在 WHERE 子句中对字段进行表达式操作,应尽量避免在 WHERE 子句中对字段进行函数操作。
9、很多时候用 EXISTS 代替 IN 是一个好的选择:select num from a where num in(select num from b)。用下面的语句替换:select num from a where exists(select 1 from b where num=a.num)。
10、索引固然可以提高相应的 SELECT 的效率,但同时也降低了 INSERT 及 UPDATE 的效。因为 INSERT 或 UPDATE 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过 6 个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
11、应尽可能的避免更新 clustered 索引数据列, 因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。
12、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。
13、尽可能的使用 varchar, nvarchar 代替 char, nchar。因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
14、最好不要使用返回所有:select from t ,用具体的字段列表代替 “*”,不要返回用不到的任何字段。
15、尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
16、使用表的别名(Alias):当在 SQL 语句中连接多个表时,请使用表的别名并把别名前缀于每个 Column 上。这样一来,就可以减少解析的时间并减少那些由 Column 歧义引起的语法错误。
17、使用“临时表”暂存中间结果 :
简化 SQL 语句的重要方法就是采用临时表暂存中间结果。但是临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在 tempdb 中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。
18、一些 SQL 查询语句应加上 nolock,读、写是会相互阻塞的,为了提高并发性能。对于一些查询,可以加上 nolock,这样读的时候可以允许写,但缺点是可能读到未提交的脏数据。
使用 nolock 有3条原则:
查询的结果用于“插、删、改”的不能加 nolock;
查询的表属于频繁发生页分裂的,慎用 nolock ;
使用临时表一样可以保存“数据前影”,起到类似 Oracle 的 undo 表空间的功能,能采用临时表提高并发性能的,不要用 nolock。
19、常见的简化规则如下:
不要有超过 5 个以上的表连接(JOIN),考虑使用临时表或表变量存放中间结果。少用子查询,视图嵌套不要过深,一般视图嵌套不要超过 2 个为宜。
20、将需要查询的结果预先计算好放在表中,查询的时候再Select。这在SQL7.0以前是最重要的手段,例如医院的住院费计算。
21、用 OR 的字句可以分解成多个查询,并且通过 UNION 连接多个查询。他们的速度只同是否使用索引有关,如果查询需要用到联合索引,用 UNION all 执行的效率更高。多个 OR 的字句没有用到索引,改写成 UNION 的形式再试图与索引匹配。一个关键的问题是否用到索引。
22、在IN后面值的列表中,将出现最频繁的值放在最前面,出现得最少的放在最后面,减少判断的次数。
23、尽量将数据的处理工作放在服务器上,减少网络的开销,如使用存储过程。
存储过程是编译好、优化过、并且被组织到一个执行规划里、且存储在数据库中的 SQL 语句,是控制流语言的集合,速度当然快。反复执行的动态 SQL,可以使用临时存储过程,该过程(临时表)被放在 Tempdb 中。
24、当服务器的内存够多时,配制线程数量 = 最大连接数+5,这样能发挥最大的效率;否则使用配制线程数量< 最大连接数,启用 SQL SERVER 的线程池来解决,如果还是数量 = 最大连接数+5,严重的损害服务器的性能。
25、查询的关联同写的顺序 :
select a.personMemberID, * from chineseresume a,personmember b where personMemberID = b.referenceid and a.personMemberID = 'JCNPRH39681' (A = B, B = '号码')
select a.personMemberID, * from chineseresume a,personmember b where a.personMemberID = b.referenceid and a.personMemberID = 'JCNPRH39681' and b.referenceid = 'JCNPRH39681' (A = B, B = '号码', A = '号码')
select a.personMemberID, * from chineseresume a,personmember b where b.referenceid = 'JCNPRH39681' and a.personMemberID = 'JCNPRH39681' (B = '号码', A = '号码')
26、尽量使用 EXISTS 代替 select count(1) 来判断是否存在记录。count 函数只有在统计表中所有行数时使用,而且 count(1) 比 count(*) 更有效率。
27、尽量使用 “>=”,不要使用 “>”。
28、索引的使用规范:
索引的创建要与应用结合考虑,建议大的 OLTP 表不要超过 6 个索引;
尽可能的使用索引字段作为查询条件,尤其是聚簇索引,必要时可以通过 index index_name 来强制指定索引;
避免对大表查询时进行 table scan,必要时考虑新建索引;
在使用索引字段作为条件时,如果该索引是联合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用;
要注意索引的维护,周期性重建索引,重新编译存储过程。
29、下列 SQL 条件语句中的列都有恰当的索引,但执行速度却非常慢:
SELECT * FROM record WHERE substrINg(card_no, 1, 4) = '5378' --13秒
SELECT * FROM record WHERE amount/30 < 1000 --11秒
SELECT * FROM record WHERE convert(char(10), date, 112) = '19991201' --10秒
分析:
WHERE 子句中对列的任何操作结果都是在 SQL 运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用该列上面的索引。
如果这些结果在查询编译时就能得到,那么就可以被 SQL 优化器优化,使用索引,避免表搜索,因此将 SQL 重写成下面这样:
SELECT * FROM record WHERE card_no like '5378%' -- < 1秒
SELECT * FROM record WHERE amount < 1000*30 -- < 1秒
SELECT * FROM record WHERE date = '1999/12/01' -- < 1秒
30、当有一批处理的插入或更新时,用批量插入或批量更新,绝不会一条条记录的去更新。
31、在所有的存储过程中,能够用 SQL 语句的,我绝不会用循环去实现。
例如:列出上个月的每一天,我会用 connect by 去递归查询一下,绝不会去用循环从上个月第一天到最后一天。
32、选择最有效率的表名顺序(只在基于规则的优化器中有效):
Oracle 的解析器按照从右到左的顺序处理 FROM 子句中的表名,FROM 子句中写在最后的表(基础表 driving table)将被最先处理,在 FROM 子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。
如果有 3 个以上的表连接查询,那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表。
33、提高 GROUP BY 语句的效率,可以通过将不需要的记录在 GROUP BY 之前过滤掉。下面两个查询返回相同结果,但第二个明显就快了许多。
低效:
SELECT JOB, AVG(SAL)
FROM EMP
GROUP BY JOB
HAVING JOB = 'PRESIDENT'
OR JOB = 'MANAGER'
高效:
SELECT JOB, AVG(SAL)
FROM EMP
WHERE JOB = 'PRESIDENT'
OR JOB = 'MANAGER'
GROUP BY JOB
34、SQL 语句用大写,因为 Oracle 总是先解析 SQL 语句,把小写的字母转换成大写的再执行。
35、别名的使用,别名是大型数据库的应用技巧,就是表名、列名在查询中以一个字母为别名,查询速度要比建连接表快 1.5 倍。
36、避免死锁,在你的存储过程和触发器中访问同一个表时总是以相同的顺序;事务应尽可能地缩短,在一个事务中应尽可能减少涉及到的数据量;永远不要在事务中等待用户输入。
37、避免使用临时表,除非确有需要,否则应尽量避免使用临时表,相反,可以使用表变量代替。大多数时候(99%),表变量驻扎在内存中,因此速度比临时表更快,临时表驻扎在 TempDb 数据库中,因此临时表上的操作需要跨数据库通信,速度自然慢。
38、最好不要使用触发器:
触发一个触发器,执行一个触发器事件本身就是一个耗费资源的过程;
如果能够使用约束实现的,尽量不要使用触发器;
不要为不同的触发事件(Insert、Update 和 Delete)使用相同的触发器;
不要在触发器中使用事务型代码。
39、索引创建规则:
表的主键、外键必须有索引;
数据量超过 300 的表应该有索引;
经常与其他表进行连接的表,在连接字段上应该建立索引;
经常出现在 WHERE 子句中的字段,特别是大表的字段,应该建立索引;
索引应该建在选择性高的字段上;
索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;
复合索引的建立需要进行仔细分析,尽量考虑用单字段索引代替;
正确选择复合索引中的主列字段,一般是选择性较好的字段;
复合索引的几个字段是否经常同时以 AND 方式出现在 WHERE 子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引;
如果复合索引中包含的字段经常单独出现在 WHERE 子句中,则分解为多个单字段索引;
如果复合索引所包含的字段超过 3 个,那么仔细考虑其必要性,考虑减少复合的字段;
如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;
频繁进行数据操作的表,不要建立太多的索引;
删除无用的索引,避免对执行计划造成负面影响;
表上建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销。另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响更大。
尽量不要对数据库中某个含有大量重复的值的字段建立索引。
40、MySQL 查询优化总结:
使用慢查询日志去发现慢查询,使用执行计划去判断查询是否正常运行,总是去测试你的查询看看是否他们运行在最佳状态下。
久而久之性能总会变化,避免在整个表上使用 count(*),它可能锁住整张表,使查询保持一致以便后续相似的查询可以使用查询缓存,在适当的情形下使用 GROUP BY 而不是 DISTINCT,在 WHERE、GROUP BY 和 ORDER BY 子句中使用有索引的列,保持索引简单,不在多个索引中包含同一个列。
有时候 MySQL 会使用错误的索引,对于这种情况使用 USE INDEX,检查使用 SQL_MODE=STRICT 的问题,对于记录数小于5的索引字段,在 UNION 的时候使用LIMIT不是用OR。
为了避免在更新前 SELECT,使用 INSERT ON DUPLICATE KEY 或者 INSERT IGNORE;不要用 UPDATE 去实现,不要使用 MAX;使用索引字段和 ORDER BY子句 LIMIT M,N 实际上可以减缓查询在某些情况下,有节制地使用,在 WHERE 子句中使用 UNION 代替子查询,在重新启动的 MySQL,记得来温暖你的数据库,以确保数据在内存和查询速度快,考虑持久连接,而不是多个连接,以减少开销。
基准查询,包括使用服务器上的负载,有时一个简单的查询可以影响其他查询,当负载增加在服务器上,使用 SHOW PROCESSLIST 查看慢的和有问题的查询,在开发环境中产生的镜像数据中测试的所有可疑的查询。
41、MySQL 备份过程:
从二级复制服务器上进行备份;
在进行备份期间停止复制,以避免在数据依赖和外键约束上出现不一致;
彻底停止 MySQL,从数据库文件进行备份;
如果使用 MySQL dump 进行备份,请同时备份二进制日志文件 – 确保复制没有中断;
不要信任 LVM 快照,这很可能产生数据不一致,将来会给你带来麻烦;
为了更容易进行单表恢复,以表为单位导出数据——如果数据是与其他表隔离的。
当使用 mysqldump 时请使用 –opt;
在备份之前检查和优化表;
为了更快的进行导入,在导入时临时禁用外键约束。;
为了更快的进行导入,在导入时临时禁用唯一性检测;
在每一次备份后计算数据库,表以及索引的尺寸,以便更够监控数据尺寸的增长;
通过自动调度脚本监控复制实例的错误和延迟;
定期执行备份。
42、查询缓冲并不自动处理空格,因此,在写 SQL 语句时,应尽量减少空格的使用,尤其是在 SQL 首和尾的空格(因为查询缓冲并不自动截取首尾空格)。
43、member 用 mid 做标准进行分表方便查询么?一般的业务需求中基本上都是以 username 为查询依据,正常应当是 username 做 hash 取模来分表。
而分表的话 MySQL 的 partition 功能就是干这个的,对代码是透明的;在代码层面去实现貌似是不合理的。
44、我们应该为数据库里的每张表都设置一个 ID 做为其主键,而且最好的是一个 INT 型的(推荐使用 UNSIGNED),并设置上自动增加的 AUTO_INCREMENT 标志。
45、在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON,在结束时设置 SET NOCOUNT OFF。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
46、MySQL 查询可以启用高速查询缓存。这是提高数据库性能的有效MySQL优化方法之一。当同一个查询被执行多次时,从缓存中提取数据和直接从数据库中返回数据快很多。
47、EXPLAIN SELECT 查询用来跟踪查看效果:
使用 EXPLAIN 关键字可以让你知道 MySQL 是如何处理你的 SQL 语句的。这可以帮你分析你的查询语句或是表结构的性能瓶颈。EXPLAIN 的查询结果还会告诉你你的索引主键被如何利用的,你的数据表是如何被搜索和排序的。
48、当只要一行数据时使用 LIMIT 1 :
当你查询表的有些时候,你已经知道结果只会有一条结果,但因为你可能需要去fetch游标,或是你也许会去检查返回的记录数。
在这种情况下,加上 LIMIT 1 可以增加性能。这样一来,MySQL 数据库引擎会在找到一条数据后停止搜索,而不是继续往后查找下一条符合记录的数据。
49、选择表合适存储引擎:
myisam:应用时以读和插入操作为主,只有少量的更新和删除,并且对事务的完整性,并发性要求不是很高的。
InnoDB:事务处理,以及并发条件下要求数据的一致性。除了插入和查询外,包括很多的更新和删除。(InnoDB 有效地降低删除和更新导致的锁定)。
对于支持事务的 InnoDB类 型的表来说,影响速度的主要原因是 AUTOCOMMIT 默认设置是打开的,而且程序没有显式调用 BEGIN 开始事务,导致每插入一条都自动提交,严重影响了速度。可以在执行 SQL 前调用 begin,多条 SQL 形成一个事物(即使 autocommit 打开也可以),将大大提高性能。
50、优化表的数据类型,选择合适的数据类型:
原则:更小通常更好,简单就好,所有字段都得有默认值,尽量避免 NULL。
例如:数据库表设计时候更小的占磁盘空间尽可能使用更小的整数类型。(mediumint 就比 int 更合适)
比如时间字段:datetime 和 timestamp。datetime 占用8个字节,timestamp 占用4个字节,只用了一半。而 timestamp 表示的范围是 1970—2037 适合做更新时间。
MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。
因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。
例如:在定义邮政编码这个字段时,如果将其设置为 CHAR(255),显然给数据库增加了不必要的空间。甚至使用VARCHAR 这种类型也是多余的,因为 CHAR(6) 就可以很好的完成任务了。
同样的,如果可以的话,我们应该使用 MEDIUMINT 而不是 BIGIN 来定义整型字段,应该尽量把字段设置为 NOT NULL,这样在将来执行查询的时候,数据库不用去比较 NULL 值。
对于某些文本字段,例如“省份”或者“性别”,我们可以将它们定义为 ENUM 类型。因为在 MySQL 中,ENUM 类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,我们又可以提高数据库的性能。
51、字符串数据类型:char, varchar, text 选择区别。
52、任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
索引优化
性能参数
问题确认:数据库分析可以提供详细的数据库性能参数。
例如MySQL数据库(当前线程连接数、连接数和最大连接数、连接失败的线程、QPS、TPS、慢查询次数相关的状态量、日志相关的状态等)。
my.ini
(1)、max_connections:
允许的同时客户的数量。增加该值增加 mysqld 要求的文件描述符的数量。这个数字应该增加,否则,你将经常看到 too many connections 错误。 默认数值是100 。
(2)、record_buffer:
每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描,你可能想要增加该值。默认数值是131072(128k) 。
(3)、key_buffer_size:
索引块是缓冲的并且被所有的线程共享。key_buffer_size是用于索引块的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),到你能负担得起那样多。如果你使它太大,系统将开始换页并且真的变慢了。默认数值是8388600(8m),我的mysql主机有2gb内存 。
4)、back_log:
要求 mysql 能有的连接数量。当主要mysql线程在一个很短时间内得到非常多的连接请求,这就起作用,然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。
back_log 值指出在mysql暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。只有如果期望在一个短时间内有很多连接,你需要增加它,换句话说,这值对到来的tcp/ip连接的侦听队列的大小。你的操作系统在这个队列大小上有它自己的限制。试图设定back_log高于你的操作系统的限制将是无效的。
当你观察你的主机进程列表,发现大量 264084 | unauthenticated user | xxx.xxx.xxx.xxx | null | connect | null | login | null 的待连接进程时,就要加大 back_log 的值了。默认数值是50 。
(5)、interactive_timeout:
服务器在关闭它前在一个交互连接上等待行动的秒数。一个交互的客户被定义为对 mysql_real_connect()使用 client_interactive 选项的客户。 默认数值是28800 。
(6)、sort_buffer:
每个需要进行排序的线程分配该大小的一个缓冲区。增加这值加速order by或group by操作。默认数值是2097144(2m) 。
(7)、table_cache:
为所有线程打开表的数量。增加该值能增加mysqld要求的文件描述符的数量。mysql对每个唯一打开的表需要2个文件描述符。默认数值是64 。
(8)、thread_cache_size:
可以复用的保存在中的线程的数量。如果有,新的线程从缓存中取得,当断开连接的时候如果有空间,客户的线置在缓存中。如果有很多新的线程,为了提高性能可以这个变量值。通过比较 connections 和 threads_created 状态的变量,可以看到这个变量的作用。
(9)mysql的搜索功能
用mysql进行搜索,目的是能不分大小写,又能用中文进行搜索
只需起动mysqld时指定 --default-character-set=gb2312
(10)、wait_timeout:
服务器在关闭它之前在一个连接上等待行动的秒数。 默认数值是28800 。
在Mysql数据库安装成功后,会在mysql根目录下存在四个.ini文件,分别为my-huge.ini、my-innodb-heavy-4G.ini、my-large.ini、my-medium.ini、my-small.ini,这几个启动配置文件中,分别对Mysql启动参数给出了如下的默认值:
存储过程procedure
存储过程时数据库的一个重要的对象,可以封装SQL语句集,可以完成复杂的业务逻辑,并且可以出入参(类似于java中的方法)。
优点:
在生产环境下,可以通过直接修改存储过程的方式修改业务逻辑(或bug),而不用重启服务器。
执行速度快,存储过程经过编译之后会比单独一条一条执行要快。
减少网络传输流量。
方便优化。
缺点:
过程化编程,复杂业务处理的维护成本高。
调试不便。
不同数据库之间可移植性差。不同数据库语法不一致!
官网
https://dev.mysql.com/doc/refman/5.6/en/sql-statements.html
https://dev.mysql.com/doc/refman/5.6/en/sql-compound-statements.html
-- 声明结束符。因为MySQL默认使用;作为结束符,而在存储过程中,会使用;作为一段语句的结束,导致;使用冲突
DELIMITER $$
-- 如果存在旧的存储过程,则删除
DROP PROCEDURE IF EXISTS 1.存储过程名称$$
-- 创建存储过程
CREATE PROCEDURE 1.存储过程名称(
2.出入参
)
BEGIN
3.变量声明及赋值
4.游标
5.HANDLER
END$$
-- 声明结束符为默认的;
DELIMITER ;
-- 注
-- 变量声明、游标声明、handler声明是必须按照先后顺序书写的,否则创建存储过程出错
DELIMITER $$
DROP PROCEDURE IF EXISTS proc_TableNameBy_FieldName_Action $$
CREATE PROCEDURE proc_TableNameBy_FieldName_Action(
in in_param_name type,
out out_param_name type,
inout inout_param_name type
)
BEGIN
-- 变量声明及赋值
-- 局部变量
-- 声明
declare field_xxx varchar(32) default 'unkown';
declare field_yyy int default 0;
-- set赋值
set field_xxx = 'ZS';
set field_yyy := 1;
-- into赋值
select t.field_xxx,t.field_yyy into field_xxx,field_yyy from table_t t;
-- 用户变量@。不需要提前声明,使用即声明
-- set赋值
set @field_xxx = 'ZS';
set @field_yyy := 1;
-- 游标CURSOR
-- 声明游标,并将sql结果集赋值到游标中
DECLARE cursor_name_xxx CURSOR FOR 查询语句;
-- 声明当游标遍历完后的标志变量
DECLARE CONTINUE HANDLER FOR NOT FOUND SET @cursor_end_flag = false;
-- 打开游标
OPEN cursor_name_xxx;
-- 循环遍历
WHILE @cursor_end_flag DO
-- 将游标中的值再赋值给变量。注意:变量名不要和返回的列名同名,变量顺序要和sql结果列的顺序一致
FETCH cursor_name_xxx INTO 变量1,变量n;
END WHILE;
-- 关闭游标
CLOSE cursor_name_xxx;
-- 执行sql返回结果集
SET @SqlCmd = 'SQL语言';
PREPARE stmt FROM @SqlCmd;
EXECUTE stmt;
-- 异常处理(非必须项)
-- EXCEPTION
END$$
DELIMITER ;
-- 调用
set @inout_param_name = 'inout';
call proc_TableNameBy_FieldName_Action('in',@out_param_name,@inout_param_name);
select @out_param_name;
select @inout_param_name;
1.存储过程名称
[proc_][TableName_][By_FieldName_][Action]
[1] [2] [3] [4]
[1] 所有的存储过程必须有前缀proc,所有的系统存储过程都有前缀sp。
假如存储过程以sp_ 为前缀开始命名那么会运行的稍微的缓慢,这是因为SQL Server将首先查找系统存储过程。
[2] 表名。存储过程主要访问的对象。
[3] 可选字段名。条件子句,比如: proc_UserInfoByUserIDSelect
[4] 最后的行为动词就是存储过程要执行的任务。
如果存储过程返回一条记录那么后缀是:Select
如果存储过程插入数据那么后缀是:Insert
如果存储过程更新数据那么后缀是:Update
如果存储过程有插入和更新那么后缀是:Save
如果存储过程删除数据那么后缀是:Delete
如果存储过程更新表中的数据 (ie. drop and create) 那么后缀是:Create
如果存储过程返回输出参数或0,那么后缀是:Output
2.入参出参
mysql
CREATE PROCEDURE 1.存储过程名称(
in in_param_name type,
out out_param_name type,
inout inout_param_name type
)
-- IN类型的入参名,要么查询的表起别名,要么入参名不与字段名一致。
-- OUT类型,只负责输出。
set @inout_param_name = 'inout';
call 1.存储过程名称('in',@out_param_name,@inout_param_name);
select @out_param_name;
select @inout_param_name;
oracle
CREATE PROCEDURE 存储过程名称(
$输入参数名1 in 数据类型,
... $输入参数名n in 表.字段%TYPE, -- 当表的数据类型更改时,自动变化,无需手动更改。
$输出参数名1 out 数据类型,
... $输出参数名n out 表.字段%TYPE -- 当表的数据类型更改时,自动变化,无需手动更改。
)
https://www.bilibili.com/video/BV1a7411Z7BN
DELIMITER $$
DROP PROCEDURE IF EXISTS 存储过程名称$$
CREATE OR REPLACE PROCEDURE 存储过程名称(
$输入参数名1 in 数据类型,
... $输入参数名n in 表.字段%TYPE, -- 当表的数据类型更改时,自动变化,无需手动更改。
$输出参数名1 out 数据类型,
... $输出参数名n out 表.字段%TYPE -- 当表的数据类型更改时,自动变化,无需手动更改。
)
AS
-- 声明变量
@变量1 数据类型;
...@变量n 数据类型;
-- 变量初始化
SELECT @变量=XXX;
SET @变量=XXX;
BEGIN
------ 业务sql语句 ------
-- 变量赋值
@变量:=值;
select XX into @变量 from 表;
SET @变量 = 值;
-- 执行sql
SET @SqlCmd = SQL语言;
PREPARE stmt FROM @SqlCmd;
EXECUTE stmt;
-- 存储过程异常处理(非必须项)
EXCEPTION
END$$
DELIMITER ;
3.变量声明及赋值
类似java中的局部变量和成员变量的声明和使用。
局部变量
用户自定义,在begin/end块中有效
begin
declare field_xxx varchar(32) default 'unkown';
declare field_yyy int default 0;
-- set赋值
set field_xxx = 'ZS';
set field_yyy := 1;
-- into赋值
select t.field_xxx,t.field_yyy into field_xxx,field_yyy from table_t t;
end$$
用户变量@
用户自定义,当前会话(连接)有效。类似java的成员变量
-- 不需要提前声明,使用即声明
begin
-- 赋值
set @field_xxx = 'ZS';
set @field_yyy := 1;
end$$
会话变量@@session
由系统提供,当前会话(连接)有效
-- 查看会话变量
show session variables;
-- 查看某会话变量
select @@session.unique_checks;
-- 修改或声明赋值会话变量
set @@session.unique_checks = 0;
全局变量@@global
由系统提供,整个mysql服务器有效
-- 查看全局变量中变量名有char的记录
show global variables like '%char%';
-- 查看全局变量character_set_client的值
select @@global.character_set_client;
4.游标CURSOR
用游标得到某一个结果集,逐行处理数据。类比jdbc的ResultSet
静态游标
-- 声明游标,并将sql结果集赋值到游标中
CURSOR 游标名称 IS 查询语句;
-- 打开游标
OPEN 游标名称;
-- 获取游标中的数据,可用limit关键字来限制条数,如果没有则默认每次抓取一条
FETCH 游标名称 INTO white_id,con;
-- 关闭游标
CLOSE 游标名称;
动态游标
-- 声明游标,并将sql结果集赋值到游标中
DECLARE 游标名称 CURSOR FOR 查询语句;
-- 声明当游标遍历完后将标志变量置成某个值
DECLARE CONTINUE HANDLER FOR NOT FOUND SET cursor_end_flag = false;
-- 打开游标
OPEN 游标名称;
-- 将游标中的值赋值给变量,获取游标中的数据。
-- 当s不等于1,也就是未遍历完时,会一直循环
WHILE cursor_end_flag DO
-- 将游标中的值再赋值给变量
FETCH 游标名称 INTO 变量1,变量n;
-- 注意:变量名不要和返回的列名同名,变量顺序要和sql结果列的顺序一致
END WHILE;
-- 关闭游标
CLOSE 游标名称;
-- 声明语法
DECLARE cursor_name CURSOR FOR select_statement
-- 打开语法
OPEN cursor_name
-- 取值语法
FETCH cursor_name INTO var_name [, var_name] ...
-- 关闭语法
CLOSE cursor_name
5.HANDLER
调用存储过程CALL
declare 输出参数名1 数据类型;
...
declare 输出参数名n 数据类型;
begin
-- 调用存储过程
存储过程名称(输入参数名1,...,输入参数名n,输出参数名1,...,输出参数名n);
dbms_output.put_line('输出结果1:'|| 输出参数名1 );
...
dbms_output.put_line('输出结果3:'|| 输出参数名n );
end;
环境搭建
MYSQL
以管理员身份运行cmd
cd mysql的bin目录
安装mysql
mysqld --install
错误 The service already exists! The current server installed
解决方案 sc delete mysql
初始化mysql,记住初始化产生的随机密码sq;97S8ktY:d
mysqld --initialize --console
开启mysql的服务
net start mysql
错误NET HELPMSG3534
解决方案 mysqld –initialize初始化data目录
ORACLE
#-------------------------依赖包下载-------------------------
#检查依赖包是否安装完全
rpm -q binutils compat-libstdc++ elfutils-libelf elfutils-libelf-devel elfutils-libelf-devel-static gcc gcc-c++ glibc glibc-common glibc-devel glibc-headers kernel-headers ksh libaio libaio-devel libgcc libgomp libstdc++ libstdc++-devel make sysstat unixODBC unixODBC-devel
#如果缺少什么就安装什么
yum install -y binutils*
yum install -y compat-libstdc*
yum install -y elfutils-libelf*
yum install -y gcc*
yum install -y glibc*
yum install -y ksh*
yum install -y libaio*
yum install -y libgcc*
yum install -y libstdc*
yum install -y make*
yum install -y sysstat*
yum install libXp* -y
yum install -y glibc-kernheaders
# yum install binutils compat-libstdc++ elfutils-libelf elfutils-libelf-devel elfutils-libelf-devel-static gcc gcc-c++ glibc glibc-common glibc-devel glibc-headers kernel-headers ksh libaio libaio-devel libgcc libgomp libstdc++ libstdc++-devel make sysstat unixODBC unixODBC-devel
##也可以一次性下载全部依赖包
yum -y install binutils compat-libcap1compat-libstdc++.i686 compat-libstdc++.x86_64 elfutils-libelf elfutils-libelf-devel gcc gcc-c++ glibc.i686 glibc.x86_64 glibc-devel.i686 glibc-devel.x86_64 ksh libgcc.i686 libgcc.x86_64 libstdc++.i686 libstdc++.x86_64 libstdc++-devel.i686 libstdc++-devel.x86_64 libaio.i686 libaio.x86_64 libaio-devel.i686 libaio-devel.x86_64 libXext libXtst libX11 libXau libxcb libXi make sysstat unixODBC-devel.i686 unixODBC-devel.x86_64 unixODBC.i686 unixODBC.x86_64 compat-libstdc++-33.i686 compat-libstdc++-33.x86_64
#------------------------- 设置用户及目录 -------------------------
#使用root用户;创建DBA用户组:oinstall和dba。
#oinstall是主要的组,用于安装数据库
groupadd oinstall
#dba是次要的组,用于管理数据库
groupadd dba
#创建用户oracle,并设置密码,一个用户可与属于多个用户组,能指定一个组为主组
#创建用户。-G表示oracle用户同时属于dba组,用于做数据维护,和数据库管理工作
useradd -G dba oracle
useradd -g oinstall -G dba,oracle
#密码设置为oracle
echo oracle|passwd --stdin oracle
#创建安装目录
mkdir -p /opt/oracle
#对目前目录下的所有文件与子目录进行相同的拥有者变更
chown -R oracle:oinstall /opt/oracle
chmod -R 775 /opt/oracle
#------------------------- 修改Linux系统参数 -------------------------
#内核参数
vim /etc/sysctl.conf文件,设置配置信号量,I/O,共享内存等参数配置。
如果该文件中已有相关参数的设置,则确保参数值不小于如下对应值;如果还没有相关参数的设置,则按照如下格式添加相应的参数设置行。
然后执行/sbin/sysctl -p生效。
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.shmall = 2097152
kernel.shmmax = 536870912
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048586
#用户管理
| Shell Limit | 在limits.conf中的项 |
| ------------------------ | ------------------- |
| 打开文件描述符的最大数量 | nofile |
| 单个用户可用的最大进程数 | nproc |
| 进程堆栈段的最大大小 | stack |
1)vim /etc/security/limits.conf添加下面的内容;修改操作系统对oracle用户资源的限制。
然后执行/sbin/limits -p生效
oracle soft nproc 2047
oracle hard nproc 16384
oracle soft nofile 1024
oracle hard nofile 65536
2)修改 /etc/pam.d/login,在文件最后添加如下内容:
session required pam_limits.so
3)vim /etc/profile添加下面内容(如果不在里面配置jdk的环境变量会报错)。
然后执行配置文件:
source /etc/profile
if [ $USER = "oracle" ]; then
if [ $SHELL = "/bin/ksh" ]; then
ulimit -p 16384
ulimit -n 65536
else
ulimit -u 16384 -n 65536
fi
fi
#环境变量
su - oracle 切换为oracle用户
cd /home/oracle
vi .bash_profile
vim /home/oracle/.bash_profile,将一下文件插入中间
export ORACLE_BASE=/opt/oracle export ORACLE_HOME=$ORACLE_BASE/appexport ORACLE_SID=数据库(实例)名 oracleSIDexport PATH=$PATH:$HOME/bin:$ORACLE_HOME/binexport NLS_LANG=AMERICAN_AMERICA.UTF8export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
执行文件生效:source .bash_profile
问题思考
mysql备份与还原
String backUpSQL = "cmd /C mysqldump -uroot -proot tistone_base tbl_ass_icareuserinfo > F:\\testdb\\base1.sql"; try { int result = Runtime.getRuntime().exec(backUpSQL).waitFor(); System.out.println("--------"+result); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }还原:Mysql -uroot -p tistone_base > f:/testdb/yuanshi.sqlMysql -uroot -p tistone_base < f:/testdb/yuanshi.sql
mysql主从复制为什么会延迟
mysql表为什么一定要有主键
为什么禁止使用事务
为什么要选择Read Committed事务隔离级别
为什么字符集以及COLLATION(排序规则)要保持一致
索引可能失效,导致数据库性能严重下降
为什么推荐使用InnoDB存储引擎
存储引擎说白了就是如何存储数据,如何为存储的数据建立索引和如何更新,查询数据等技术的实现方法。mysql以插件(plugin)的形式提供不同的存储引擎,常见的存储引擎有InnoDB,MyISAM,ARCHIVE,MEMORY,CSV等(在oracle和SQL Server等数据库中只有一种存储引擎)。
生产环境的标准是使用InnoDB引擎。
为什么要给表加上主键?
为什么加索引后会使查询变快?
为什么加索引后会使写入、修改、删除变慢?
什么情况下要同时在两个字段上建索引?
锁
逻辑架构
Mysql
MySQL服务器逻辑架构从上往下可以分为三层:
1)第一层:处理客户端连接、授权认证等。
2)第二层:服务器层,负责查询语句的解析、优化、缓存以及内置函数的实现、存储过程等。
3)第三层:存储引擎,负责MySQL中数据的存储和提取。MySQL中服务器层不管理事务,事务是由存储引擎实现的。MySQL支持事务的存储引擎有InnoDB、NDB Cluster等,其中InnoDB的使用最为广泛;其他存储引擎不支持事务,如MyIsam、Memory等。
Oracle
oracle服务器=数据库+实例;
实例=分配内存结构+管理数据库的后台线程
用户–会话–>数据库
启动数据库实例–>sqlplus连接到数据库–>创建用户进程–>创建服务器进程–>提交sql查询