1)首先可以明确的是char是定长的,而varchar是可变长。
2)在存储方式上,char对英文字符(ASCII)占用1字节,对一个汉字使用用2字节。而varchar对每个字符均使用2字节。
索引是对数据库表中一列或多列的值进行排序的数据结构,用于快速访问数据库表中的特定信息。
1)从物理结构上可以分为聚集索引和非聚集索引两类:
2)从应用上可以分为:
ALTER TABLE table_name ADD INDEX index_name (column)
ALTER TABLE table_name ADD INDEX index_name (column)
优点: 创建索引可以大大提高系统的性能。
缺点:
索引的数据结构和具体存储引擎的实现有关,MySQL中常用的是 Hash 和 B+树 索引。
Hash:查询时调用Hash函数获得地址,回表查询实际数据。(InnoDB和MylSAM不支持,Memory支持)
B+Tree:每次从根节点出发去查询,然后得到地址,回表查询实际数据。
因为可以加速查询效率,而且可以保持有序。
二叉查找树:一个节点最多两个子节点(左小右大),查询次数和比较次数都是最小的,但是索引是存在磁盘的,当数据量过大时,不能直接把整个索引文件加载到内存,需要分多次IO,最坏的情况IO的次数就是树的高度,为了减少IO,需要把树从竖向变为横向。
B树(B-):是一种多路查询树,每个节点包含K个子节点,节点都存储索引值和数据,K是B树的阶(树高被称为树的阶)。虽然比较的次数比较多,但是是在内存的比较,可以忽略不记,但是B树IO的次数要比二叉查找树要少,因为B树的高度可以更低。
B+树:B树的升级版,只有叶子节点存储的是索引值指向的数据库的数据。
1)B树只适合随机检索,而B+树同时支持随机检索和顺序检索(因为叶子节点相当于链表,保存索引值都是有序的)
顺序检索:按照序列顺序遍历比较找到给定值。
随机索引:不断从序列中随机抽取数据进行比较,最终找到结果。
2)减少了磁盘IO,提高空间利用率:因为B+树非叶子节点不会存放数据,只有索引值,所以非叶子节点可以保存更多的索引值,这样B+树就可以更矮,减少IO次数。
3)B+树适合范围查找:这是关键,数据库大部分都是范围查找。B+树的叶子节点是有序链表,直接遍历就行,而B树的范围查找可能两个节点距离很远,只能通过中序遍历去查找,索引使用B+树更合适。
页(Page):
首先 InnoDB 将物理磁盘划分为页(page),每页的大小默认 16KB,页是最小的存储单位。页根据上层应用的需要,如索引、日志等,分为很多的格式。我们主要说数据页,也就是存储实际数据的页。
区(Extent):
如果只有页这一个层次的话,页的个数是非常多的,存储空间的分配和回收都会很麻烦,因为要维护这么多的页的状态是非常麻烦的。所以,InnoDB 又引入了区的概念。一个区默认64个连续的页组成,也就是1MB.
段(Segment):
为什么要引入段呢,这要从索引说起。我们都知道索引的目的是为了加快查找速度,是一种典型的用空间换时间的方法。 B+ 树的叶子节点存放的是我们的具体数据,非叶子节点是索引页。所以B+树将数据分为了两部分,叶子节点部分和非叶子节点部分,也就是段。
数据库的事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务是对数据库中一系列操作进行统一的回滚或者提交操作,主要用来保证数据的完整性和一致性。
不可重复读和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增和删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(Read uncommitted) | √ | √ | √ |
读已提交(Read committed) | × | √ | √ |
可重复读(Repeatable read) | × | × | √ |
可串行化(Serializable) | × | × | × |
当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。即锁的作用是解决并发问题。
共享锁(Share Lock):S锁,有称读锁,用于所有的只读数据操作。S锁并非独占,允许多个并发事务对同一资源加锁,但加S锁的同时不允许加X锁,即资源不能被修改。S锁通常读取结束后立即释放,无需等待事务结束。
排他锁(Exclusive Lock):X锁,又称写锁,表示对数据进行写操作。X锁仅允许一个事务对同一资源加锁,且直到事务结束才释放,其他任何事务必须等到X锁被释放才能对该页进行访问。使用以下语句产生X锁。
select * from table_name for update;
更新锁:U锁,用来预定要对资源施加X锁,允许其他事务读,但不允许再施加U锁或X锁。
通常SQL语句可以分为两类:
sum(列名) 求和
max(列名) 最大值
min(列名) 最小值
avg(列名) 平均值
first(列名) 第一条记录
last(列名) 最后一条记录
count(列名) 统计记录数
内连接 (自然连接):查询两个表匹配数据。只返回匹配的行,如 Inner Join、Union Join。
外连接:返回一个表的全集,如 Left、Right、Full 和 Cross.
左连接:查询左表全部行以及右表匹配的行
右连接:查询右表全部行以及左表匹配的行
where 子句的作用是对查询结果进行分组前,将不符合条件的行去掉,即在分组之前过滤数据,where条件中不能包含聚组函数,使用where条件过滤出特定的行。
having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having条件过滤出特定的组,也可以使用多个分组标准进行分组。
总结下条件的过滤顺序:on -> join -> where -> group by -> having
from -> ON 主表过滤 -> join 外部连接 -> where -> group by 分组 -> having 分组后 -> select -> distict 去重 -> order by 排序 -> limit(分页) 0,10
in():适合子表(子查询)比主表数据小的情况
exists():适合子表(子查询)比主表数据大的情况
explain命令是查看查询优化器如何决定执行查询的主要方法,使用explain只需在查询语句开头增加explain这个关键字即可。
说到MySQL的分页,我们首先想到的就是 offset、limit 操作,但随着页数的增加,查询性能指数级增大。
这是由于MySQL并不是跳过 offset 的行数,而是取 offset + limit 行,然后丢弃前 offset 行,返回 limit 行,当 offset 特别大的时候,效率就非常低下。
此处我们采用 覆盖索引+延迟关联 技术来减少偏移量的定位进行优化。
##查询语句
select id from product limit 10000000, 10
##优化方式一
SELECT * FROM product WHERE ID > =(select id from product limit 10000000, 1) limit 10
##优化方式二
SELECT * FROM product a JOIN (select id from product limit 10000000, 10) b ON a.ID = b.id
可以从SQL优化、分库分表、读写隔离以及缓存四个维度分别阐述
排查:
优化:
sql优化 + 索引 + 数据库结构优化 + 优化器优化
一般drop table if exists是数据库里面的,后面接表名如:drop table if exists xxx_book意思就是:如果数据库中存在xxx_book表,就把它从数据库中drop掉。
备份sql中一般都有这样的语句,如果是数据库中有这个表,先drop掉,然后create表,然后再进行数据插入。
select * from 表名
二种方式:
1.distinct 关键字select distinct university from user_profile distinct去重,放在列的前面使用。2.分组select university from user_profile group by university;以分组来筛选出去重的结果
select device_id from user_profile limit 0,2---运行效率更高
select device_id from user_profile limit 2 ---运行效率低
也可结合 limit offset: 一起使用时,limit表示要取的数量,offset表示跳过的数量
select device_id from user_profile limit 2 offset 0 // 跳过0条,从第一条数据开始取,取两条数据 ---运行效率中
select device_id as user_infors_example from user_profile limit 0,2;
这里主要是用到了 起别名关键字 as 以及组合限制查询 limit 索引,个数
其中as可以省略,索引为0可以省略
select device_id user_infors_example from user_profile limit 2;
SELECT device_id, gender,age,university FROM user_profile WHERE university NOT IN ("复旦大学")
字符匹配
一般形式为:列名 [NOT ] LIKE
匹配串中可包含如下四种通配符:
- _:匹配任意一个字符;
- %:匹配0个或多个字符;
- [ ]:匹配[ ]中的任意一个字符(若要比较的字符是连续的,则可以用连字符“-”表 达 );
- [^ ]:不匹配[ ]中的任意一个字符。
例:查询学生表中姓‘张’的学生的详细信息。
SELECT * FROM 学生表 WHERE 姓名 LIKE ‘张%’
例:查询姓“张”且名字是3个字的学生姓名。
SELECT * FROM 学生表 WHERE 姓名 LIKE '张__’
例:查询学生表中姓‘张’、姓‘李’和姓‘刘’的学生的情况
SELECT * FROM 学生表 WHERE 姓名 LIKE '[张李刘]%’
例:查询学生表表中名字的第2个字为“小”或“大”的学生的姓名和学号。
SELECT 姓名,学号 FROM 学生表 WHERE 姓名 LIKE '_[小大]%'
例:从学生表表中查询学号的最后一位不是2、3、5的学生信息。
SELECT * FROM 学生表 WHERE 学号 LIKE '%[^235]'
SELECT device_id,age,university FROM user_profile
WHERE university LIKE '%北京%'
# 方法1
select max(gpa) as gpa
from user_profile
where university='复旦大学';
# 方法2
select gpa
from user_profile
where university='复旦大学'
order by gpa desc limit 1 (desc升序,asc降序)
问题分解:
- 限定条件为 男性用户;
- 有多少人,明显是计数,count函数;
- 平均gpa,求平均值用avg函数;
细节问题:根据输出示例,有两个问题需要注意:
- 表头重命名,用as语法
- 浮点数的平均值可能小数点位数很多,按照示例保存一位小数,用round函数
select
count(gender) as male_num,
round(avg(gpa), 1) as avg_gpa
from user_profile where gender="male";
现在运营想查看每个学校用户的平均发贴和回帖情况,寻找低活跃度学校进行重点运营,请取出平均发贴数低于5的学校或平均回帖数小于20的学校。