数据库知识点总结

实习/秋招时按自己需求总结的知识点,内容并不十分详细,建议选择性阅读。

MySQL默认端口号3306
命令行连接数据库:

mysql -h127.0.0.1 -uroot -proot -P3306
show databases;
use dbname;
show tables;

mysqldump -hhost -uuser -ppwd -P3315 dbname tablename \
--where='true limit 1000' \ # 按条件导出
--skip_lock_tables \        # 去除表的锁定(锁定了导不出去)
--complete_insert \         # 显示完成的插入
--skip_extended_insert \   # 一条一条插入
-d \# 只导出表结构,不导出数据
out.sql

范式

  • 第一范式,列不可分,即有的列还能继续划分但是没有
  • 第二范式,有主键,需完全依赖主键
  • 第三范式,无传递依赖,即非主键A依赖非主键B,非主键依赖主键C的情况
  • BC范式,任何非主属性不能对主键子集依赖,是第三范式的扩充

数据库的完整性

  • 域完整性,取值约束,不能为非法值
  • 实体完整性,主键不能为空
  • 参照完整性,外键要么为空,要么为已存在的值

索引

在一列或多列字段上建立索引,已达到快速查询的目的
使用范围:

  • 经常做查询的字段
  • group by,order by,distinct后连接的字段
  • 用作表连接的字段

创建索引的较佳实践:

  • 在非空字段上创建,因为B+树遇到空值时会更难以处理,且难以优化
  • 选取值比较离散的字段
  • 索引字段越小越好。数据库的数据存储以为单位,一页存储的数据越多,一次IO操作获取的数据也越大,效率就越高

会使索引失效的情况

  • where子句中用 !=, <>判断是否为null的语句
  • 模糊查询中,like语句时用了 %
  • 数据类型出现隐式转换
索引类型

https://www.cnblogs.com/gaoquanquan/p/11030999.html

  • 唯一索引,字段的值为唯一
  • 普通索引
  • 全文索引

按组织方式分

  • 聚集索引,InnoDB的存储引擎表是索引组织表,表中的数据是根据主键按顺序存放的,聚集索引根据主键来构造B+树,叶子结点存放的是该主键所在行的完整数据,每个表中只能有一个
  • 非聚集索引,又称辅助索引,二级索引,每个表可以有多个非聚集索引。之所以引入非聚集索引,是因为其构造的B+树存放的是主键,而不是完整数据,因此占用的空间较少,通常使用非聚集索引时,先查到主键,再根据主键到聚集索引中找到完整的行

聚集索引:主键
非聚集索引:唯一索引,普通索引,前缀索引

在数据量很大同时某个字段取值范围很小的情况下,B树的深度会很浅,每个结点包含的数据量很大,此时难以体现B树的优势,应使用位图索引,位图索引在Oracle中实现
位图索引

  • 适用于取值范围很小的字段,如性别,婚姻状况
  • 对于这一字段的取值,若符合某一条件,则为1,否则为0,通过这一设置,可以通过位操作很方便的取得想要的数据
  • 更新位图索引时,所有数据都会被锁定,因此不适合OLTP,不适合频繁修改的环境,只适合查询系统

概念区分
1.主键唯一索引且不为空
2.自增主键,自动增加的主键,字段类型为数字
3.主键索引,主键是一种特殊的索引
4.唯一索引,索引列的值必须唯一,但可以为空。主键是唯一索引
5.主键和聚集索引。InnoDB在创建主键时,默认将主键设置为聚集索引。创建表时,若未设定主键,则会将唯一非空的字段设为主键;若未找到,则会创建一个隐藏的聚集索引主键

索引的优点
  • 加快查询
  • 加速表与表之间的连接
  • 减少分组和排序的时间
  • 创建唯一性索引保证字段的唯一性
索引的缺点
  • 索引需要花费时间动态维护
  • 索引需要额外的物理空间来存储
B-树

一种平衡多路查找m叉树,AVL或红黑树在数据量非常大的时候,较深的树结构会导致查询效率变低,m叉树每个结点保存多个值,使得其保持较低的高度,因而效率仍较高

一棵m叉树的定义为:

  • 每个结点至多有m个子节点
  • 除根节点外,每个结点至少有m/2(向上取整)个子节点
  • 根节点至少有2个子节点
    通常,m>=3

在这里插入图片描述

每个结点包含的值是个有序表,可表示为:

(n,A0,K1,A1,K2,A2,….,Kn,An)

  • n为该结点值的个数;
  • Ki(i=1,2,…,n)为关键码,且Ki < K(i+1),
  • Ai 为指向子树根结点的指针(i=0,1,…,n),且指针A(i-1) 所指子树中所有结点的关键码均小于Ki (i=1,2,…,n),An 所指子树中所有结点的关键码均大于Kn.
B+树

B-树的变种,是InnoDB存储引擎的实现

  • 非叶子结点存储的是指针
  • 非叶子结点的子树指针个数为m;
  • 所有的关键码都存放在叶子结点中,以有序链表存放;
  • 有一个指向叶子结点的指针,用于遍历该有序链表

1.由于关键码存放在叶子结点中,因此查找时必经历一条从根到叶结点的完整路径
2.由于有一个指向叶子结点的指针,因此遍历所有关键码更为方便,而B-树则需要中序遍历,效率更低
在这里插入图片描述

B*树

在B+树的基础上增加了非叶子结点指向兄弟结点的指针,空间利用率比B+树高

在这里插入图片描述

存储过程

预先编译好的一组SQL语句,方便执行一组操作,使用时调用即可

  • 提高执行效率,存储过程只在创建时编译一次,以后调用即可,而执行SQL语句每执行一次就要编译一次,因此存储过程缩短了执行时间
  • 减少网络传输,在客户端调用存储过程的开销比执行一串SQL传输的语句更小
  • 提高安全性,用户可以在不接触数据的情况下通过存储过程访问数据库,提升了安全性
为什么禁用存储过程

阿里的开发手册禁用存储过程,查了一下,原因如下:

  • 难以调试
  • 减少的网络传输其实并没有那么多
  • 存储过程只编译一次,在大业务量环境下反而成为劣势,随着数据增大或变动,需要重编译或修改存储过程

https://blog.csdn.net/HoneyYHQ9988/article/details/96773210

drop,truncate,delete的区别

  • drop,删除表
  • truncate,清空表中的数据
  • delete,删除表中的部分或全部数据
    删除表中的部分数据,用delete
    清空表中的数据,truncate效率比delete
    删除表,用drop

内连接,外连接和全表连接

  • 内连接
    至少返回一个匹配结果,若不存在,则不返回
  • 外连接
    分为左外连接和右外连接,若不存在,则某字段为
    left join时结果可能会大于实际的数据,原因在于部分数据值相同(可以用group by解决?)
  • 全表连接
    将两个表连接
select a.email from person a join person b on a.email=b.emial and a.id != b.id
SQL语句

show databases;
use databasename; use tablename;

  • insert into on duplicate key update:在表中插入数据,若已存在,则更新
insert into table(id, name) values(2, 'larry') on duplicate key update name='lairay'
如果不想更新,就写成:
insert into table(id, name) values(2, 'larry') on duplicate key update name=name;
  • insert into select from:从表1中复制数据插入到表2
insert into table1(id, name) select tid as id, tname as name from table2;
  • GROUP_CONCAT函数:从表中查询多个数据,若同名则以逗号隔开

https://baijiahao.baidu.com/s?id=1595349117525189591&wfr=spider&for=pc

select GROUP_CONCAT(name separator ','), score from students group by score; # 查询所有学生的分数,按分数高低排序,分数相同用逗号隔开

select t1.id, t1.status, group_concat(t1.name separator ','), t2.id, t2.name  from test t1 left join test1  t2 on t1.name=t2.name group by t1.id;
  • 查询所有分数及格和不及格的学生,按班级分组
select class, sum(case when grade >= 60 then 1 else 0 end), sum(case when grade < 60 then 1 else 0 end) from A group by class;

group by详解

https://www.jianshu.com/p/8b135d373df1

语法:
select name1, aggregate_func(name2) from table where name3 operator value group by name2;
  • 使用having子句筛选group by的结果

replace函数

https://blog.csdn.net/lanxingbudui/article/details/83854735
TRIM函数

https://www.1keydata.com/cn/sql/sql-trim.php

优化

SQL语句优化
  • where子句中避免用!= <>以及null判断
  • 子句嵌套查询尽量改为连接查询
  • 尽量使用exists代替in
  • insert时一次插入多条数据
  • 使用union代替or
SQL表优化
  • 选择合适的数据类型
  • 垂直拆分,将列多的表拆为多个表,拆分思路为:经常使用的,不经常使用的,经常查询的列
  • 水平拆分,将数据量大的表按行拆为多个表,可以提高查询速度,即分库,这种设计适合于需要保存历史订单的情况。例如,某个平台的订单不断增加,而用户实际使用的只是近期订单,因此可以考虑把历史订单水平拆分,提升查询速度
慢查询日志

记录了超过long_query_time的SQL语句
慢查询日志有mysqldump, pt_query_digest
可以查询的有:

  • 超过long_query_time的SQL语句
  • 超时的次数
  • 总的超时时间
  • 发给客户端的行数
  • 在总时间的占比

事务

事务是指向数据库提交一组操作,是一个不可分割的操作序列,使数据库从一个一致性状态转移到另一种一致性状态

事务的特性ACID
  • Atomicity原子性,指事务的操作要么全做,要么全不做
  • Consistency一致性,事务的操作会使数据库从一个一致性状态转移到另一个一致性状态
  • Isolation隔离性,事务的操作不会对别的事务造成影响,也不会被的事务影响
  • Durability持久性,事务一旦提交,对数据库的影响是永久性的
并发事务的问题
  • 脏读
    事务可能会读取到另一个事务未提交的数据
  • 不可重复读
    事务对同一数据的两次读的结果不同,原因在于期间被别的事务修改
  • 幻读
    重点在于新增或删除,使得读出的记录数不一样

要解决脏读和不可重复读问题,需要利用MVCC,即多版本并发控制
每个事务会有版本号,在写操作时更新版本快照,读操作时只到旧版本快照读,以此解决读到了别人未提交的数据(脏读)以及两次读的结果不同(不可重复读)的问题
而幻读则需要next-keys算法

  • record-locks
    锁的是记录上的索引,而不锁数据本身
  • gap locks
    锁一个索引范围
  • next-key locks
    record+gap lock,既锁记录上的索引,也锁索引范围
事务的隔离级别
  • READ UNCOMMITTED
    最低级别,允许事务读取另一个事务未提交的数据,会导致脏读问题

  • READ COMMITTED
    事务只能读取其他事务已提交的数据,但无法避免不可重复读的问题

  • REPEATABLE READ
    MYSQL的默认隔离级别,在一个事务中,其他事务对该数据库的修改对本事务不可见,避免了不可重复读的问题,但是无法避免幻读

  • SERIALIZABLE
    最高级别,只允许事务串行执行

mysql中的事务

https://www.qttc.net/175-mysql-autocommit.html

set autommit=0/off,该设置使得要执行的mysql语句一直处于事务中,直到执行commit或rollback语句才会开始一条新的事务
如:

% 以下语句开启一个事务
set autocommit=0;
% or
set autocommit=off;

insert ...; % 插入一条语句
rollback;   (如果insert失败)
update ...;
rollback;   (如果update失败)
commit; (提交事务,该事务结束)
commit and chain; (链式事务。提交事务,并开启下一个事务)
commit work;    (若completion_type=0,则该命令效果与commit一致;若completion_type=1,则变为链式事务。completion_type默认为0)
commit and release; (提交事务并断开mysql服务器连接)
分布式事务

https://juejin.im/post/6844903573667446797

防sql注入
/*

 * 检测字符串里是否含有特殊字符,防sql注入

 */

bool db_escape_string(const string &from)

{
    bool flag = true;
    size_t size = from.length();
    const char* data = from.c_str();
    for (size_t i = 0; i < size; ++i)
    {
        switch (*data) {
        case 0:             /* Must be escaped for 'mysql' */
        case '\n':              /* Must be escaped for logs */
        case '\r':
        case '\\':
        case '\'':
        case '"':               /* Better safe than sorry */
        case '\032':            /* This gives problems on Win32 */
        case ';':
        case '%':
            flag = false;
            break;
        }
        data++;
    }
    return flag;
}

  • 粒度,表级锁,行级锁,页级锁
  • 级别,共享锁,排它锁,意向锁
  • 加锁方式,自动锁和显示锁
  • 使用方式,乐观锁,悲观锁
按粒度的锁
  • 行级锁,粒度最细,并发最高,开销最大,发生锁冲突概率最低
  • 表级锁,粒度最粗,并发最低,开销最小,加锁速度最快,锁冲突概率最高
  • 页级锁,在行级和表级之间,一次锁定一组相邻记录作为“页”
级别
共享锁Shared

若事务加上共享锁,则其他事务也能加共享锁

排它锁eXclusive

若事务加上排它锁,则其他事务不能加任何锁

意向锁

若事务A对某行加了行级共享锁,则其他事务可以共享读;但是如果有事务B对整个表加了排它写锁,那理论上就可以对该行进行写,因此会产生冲突
意向锁的作用在于:先检测该表有没有其他事务使用行级共享锁,如果有,则被阻塞

乐观锁

先修改数据库,在提交时再判断数据库是否被修改,若被修改过,则失败,否则成功,判断是否被修改的方式是在要锁的数据中添加一个版本号时间戳

注:
这种做法被称为多版本并发控制MVCC,例如,在InnoDB的实现中,事务在修改一行后,会增加两个隐藏列,分别保存系统版本号过期时间,用于比对其是否被修改过

MySQL中MVCC的正确打开方式
https://blog.csdn.net/Waves___/article/details/105295060#4%E3%80%81%E5%BD%93%E5%89%8D%E8%AF%BB%E5%92%8C%E5%BF%AB%E7%85%A7%E8%AF%BB

悲观锁

在修改数据库之前,先获取该数据上的锁,若获取成功,则修改,否则等待
Oracle中可以添加no wait选项,使得在没有获取锁时立即报错

乐观锁和悲观锁适用范围

读多写少乐观锁,读少写多悲观锁

存储引擎

MyISAM

MySQL Indexed Sequential Access Method

  • MySQL5.5之前的默认数据库引擎,速度快,效率高,但是不支持事务,不支持并发,不支持外键
    先有MyISAM后有InnoDB
  • MyISAM只支持表级锁,InnoDB支持行级锁

CAP理论

  • Consistency 一致性
  • Availablity可用性
  • Partition tolerance 分区容错性
    实际最多只能满足其中一项

数据库的主从复制

一台作为主服务器,其余多台用于读
优点

  • 用于热备份,在数据损坏时可用于恢复;
  • 提升IO性能,采用一台数据库时在面临大数据量访问的时候会产生瓶颈,从数据库达到分流的目的,从而提升IO性能
  • 读写分离,通常主库写,从库读,主从之间做同步
实现过程
  • 主数据库的更新操作写入binlog
  • 从数据库连接到主数据库;
  • 主数据库开辟一个线程,将binlog更新的内容发送至从数据库;
  • 从数据库开辟一个IO线程,读取来自binlog的数据并写入到relay log
  • 从数据库创建一个线程从relay log中读取内容并更新从数据库。注意
    relay log中有一个Exec_Master_Log_Pos用于记录当前更新到了哪个位置,每次从这个pos开始做同步
主服务器宕机的解决方案

通常,若主服务器宕机,则需要将某一台从服务器设为主服务器,过程为:

  • 确保所有relay log更新完毕,命令查看:show processlist
  • 登陆从数据库,查看master.info,对比最大的Exec_Master_Log_Pos作为主数据库;
  • stop slave,删除master.info和relay.log,配置my.cnf,开启binlogreset master
主从数据库复制延迟的解决方案

MySQL默认的复制是异步的,即主数据库写数据后会立即返回给客户端,此时若主机宕机,可能导致数据丢失

半同步复制

MySQL5.5之后以插件形式支持

主库写完后,保证至少写入到一个从库的relay log才返回给客户端,优点是避免了数据丢失问题,提升了安全性,缺点是有一定的延迟,至少是一个TCP往返时间,因此会有一定的性能降低

数据库中间件

读写操作都经过中间件

  • 写操作
    将写操作记录到中间件中,设置一个同步的经验时间,例如500ms,然后修改主数据库并进行同步
  • 读操作
    先访问中间件,若在同步时间内,说明主库被修改,路由到从主库读;
    若没有数据,说明没有被修改,路由到从库读
数据库恢复

需确保开启binlog功能

https://www.cnblogs.com/aqiao1819/p/10681688.html

https://blog.csdn.net/mengzuchao/article/details/81674460

# 导出表
mysqldump -h10.56.44.111 -uncs -pncs -P3307 rc_conf t_oss_sid  >  t_oss_sid.sql
mysqldump -hhost -uuser -ppwd -P3315 dbname tablename \
--where='true limit 1000' \ # 按条件导出
--skip_lock_tables \        # 去除表的锁定(锁定了导不出去)
--complete_insert \         # 显示完成的插入
--skip_extended_insert \   # 一条一条插入
-d # 只导出表结构,不导出数据
> out.sql 
# 导入表到另一个数据库
mysql -h10.56.44.111 -uncs -pncs -P3315 -A rc_conf < t_oss_sid.sql


全文检索

可以通过索引来模糊查询:

select * from blog where content like 'MYSQL%';

只会查询MYSQL开头的数据,但是如果想要查文章中包含MYSQL的数据就做不到了,这时候就需要能全文检索,这是MySQL的InnoDB引擎1.2版本以后实现的功能
全文检索采拥倒排索引实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值