索引是什么?
索引是高效获取数据的数据结构。
索引可以是hash的,可以是B+Tree的,hash索引存放在内存中,B+Tree存放在硬盘中
自适应hash索引(innodb引擎)
数据量大时内存占用大;只支持等值查询;对范围查询和排序支持不好。
哪种存储引擎支持手动hash索引?
memory,因为它将数据放在内存中。适合做中间表
AVL树为什么不能做索引的存储结构?
数据量大会导致树变深,增加查询IO次数;每个节点关键字只有一个,每次IO拿到数据太少(pagesize=16kb)
BTree为什么不做索引的存储结构?
最多关键字个数=路数-1
每个节点三部分:关键字,数据区,子节点指针。数据区理解为数据存储在磁盘中的位置,相当于磁盘指针
瘦高的树变为矮胖的树,减少IO次数,节点关键字变多,每次IO拿到的数据变多
B+Tree为什么作为索引存储结构?
基于索引排序和范围查找能力更强;基于索引的扫库扫表能力更强;查询时间稳定;取消了数据区使读写能力更强
B+Tree怎么存储?
都存在硬盘中,但myisam和innodb存储引擎有差别
myisam引擎有myd和myi文件,一个存放索引,一个存放数据。无论是主键索引还是非主键索引,都是查询到叶子节点,
叶子节点中存放的是磁盘指针,根据指针值在myd文件中获取具体内容。
innodb引擎中只有ibd文件,叶子节点直接挂载的是真正的行记录,根据主键查到后直接返回行记录。非主键索引的叶子节点存放的是索引列的值和主键的值。
根据非主键索引查到主键id,再根据主键ID找到行记录
聚集索引和非聚集索引
innodb引擎中,只有主键是聚集索引,其他都是非聚集索引
myisam引擎中,都是非聚集索引
手动建立主键索引的好处
列的离散型
对离散型好的列建立索引,因为计算机在BTree中能清楚的知道走那一路,如果用离散型不好的列,例如sex建立索引,计算机不知道走哪一路,会都不走,变成无效索引联合索引
例如name+phone+age联合索引,相当于建立了三列的索引: name, name+phone, name+phone+age 是从左到右建立搜索树的。如果查询条件改为"dafei+18"会比较name找出所有叫dafei的,再依次比较其中的age。
范围之后全失效
例如where name=dafei and phone>130000 and age=18
只生效了name和phone索引,因为name和phone筛选过后还有很多数据,条条大路通罗马,会都不走。这是索引的离散性。
优化器
连接器,分析器,优化器,执行器
like "dafei%" 会不会走索引?
这要看数据的离散性,如果是"aily","tom","dafei"这种数据,查询结果只有一个,会走索引,因为内部是ascii码值,会根据d分路,再根据a分路,依次类推。
覆盖索引
查询的时候没有回表操作,直接返回数据叫覆盖索引。
三星索引
1.where后面匹配的索引关键字列越多越好,扫描的数据越精确越少越好-通过索引筛选出的数据越少越好
2.避免再次排序(order by最好是索引列)
慢查询是日志文件,记录查询时间超过阈值的sql语句
配置文件中
log-output=FILE #存储在文件中,可以是表,但不推荐
general-log=0 #未开启,不知道是什么
general-log-file="xxx.log"
slow-query-log=1 #开启慢查询
slow-query-log-file="xxx.log" #慢查询日志存放位置
long-query-time=10 #阈值,单位秒
如何查找慢查询日志中的哪些sql最慢?
perl mysql/bin/mysqldumpslow.pl -s t -t f:xx.log (说明:第一个t表示按时间排序,第二个-t表示取前面5条)
常见优化方式
1、服务器硬件(略) 机械硬盘_固态硬盘
2、mysql服务器(略) linux-windows
3、sql本身优化
1)【强制】不要使用 count(列名)或 count(常量)来替代 count(*),count(*)是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
正例:使用如下方式来避免 sum 的 NPE 问题:SELECT IFNULL(SUM(column), 0) FROM table;
4)【强制】使用 ISNULL()来判断是否为 NULL 值。 说明:NULL 与任何值的直接比较都为 NULL。
(1) NULL<>NULL 的返回结果是 NULL,而不是 false。
(2) NULL=NULL 的返回结果是 NULL,而不是 true。
(3) NULL<>1 的返回结果是 NULL,而不是 true。
说明:以学生和成绩的关系为例,学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。
外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。
7) 【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。11)【参考】如果有国际化需要,所有的字符存储与表示,均以 utf-8 编码,注意字符统计函数的区别。
说明:
SELECT LENGTH("轻松工作"); 返回为 12
SELECT CHARACTER_LENGTH("轻松工作"); 返回为 4
说明:TRUNCATE TABLE 在功能上与不带 WHERE 子句的 DELETE 语句相同。
4、反范式设计优化
范式化是为了减少冗余,对增,删,改比较友好,对查询不友好
例如:where status=1 or status=2可以冗余字段,优化成 where status12=true
正例:商品类目名称使用频率高,字段长度短,名称基本一不变,可在相关联的表中冗余存储类目名称,避免关联查询。
5、物理设计优化 (字段类型,长度设计,存储引擎)当一个列可以选择多种数据类型时,优先考虑数字类型,其次是日期/时间类型,最后是字符类型,能使用char的不使用varchar,对于相同级别的类型,应该优先选用占用空间小的数据类型
4)表必备三字段:id, create_time, update_time。说明:其中 id 必为主键,类型为 bigint unsigned、单表时自增、步长为 1。create_time, update_time的类型均为 datetime 类型。
5)合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。
对象 年龄区间 类型 字节 表示范围
人 150 岁之内 tinyint unsigned 1 无符号值:0 到 255
龟 数百岁 smallint unsigned 2 无符号值:0 到 65535
恐龙化石 数千万年 int unsigned 4 无符号值:0 到约 42.9 亿
太阳 约 50 亿年 bigint unsigned 8 无符号值:0 到约 10 的 19 次方
6、索引优化
普通索引: 即一个索引只包含单个列,一个表可以有多个单列索引
唯一索引: 索引列的值必须唯一,但允许有空值
主键索引: 只要创建了主键就有主键索引。主键索引跟唯一索引的区别是不能为空
复合索引: 即一个索引包括多个列
聚集索引: 并不是一种单独的索引类型,而是一种数据存储方式,具体细节取决于不同的实现,在同一个结构中保存了B+Tree和数据行,比如innodb引擎。innodb中只有主键索引是聚集索引,其他都是非聚集索引。
非聚集索引: 除了聚集索引,其他的都是非聚集索引。 innodb引擎中出了主键,其他都是非聚集索引,myisam引擎中都是非聚集索引。
优化策略:范围条件放最后,建索引的时候,和查询的时候
说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外
即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。
说明:即使双表 join 也要注意表索引、SQL 性能。
4)【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度即可。说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度来确定。
5)【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。说明:索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。
6)【推荐】如果有 order by 的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。
正例:where a=? and b=? order by c; 索引:a_b_c
反例:索引如果存在范围查询,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引 a_b 无法排序。
说明:MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行,那当offset 特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL改写。
正例:先快速定位需要获取的 id 段,然后再关联: SELECT a.* FROM 表 1 a, (select id from 表 1 where 条件 LIMIT 100000,20 ) b where a.id=b.id
说明:
(1) consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。
(2) ref 指的是使用普通的索引(normal index)。
(3) range 对索引进行范围检索。
反例:explain 表的结果,type=index,索引物理文件全扫描,速度非常慢,这个 index 级别比较 range还低,与全表扫描是小巫见大巫。
10)【推荐】建组合索引的时候,区分度最高的在最左边。
正例:如果 where a=? and b=? ,如果 a 列的几乎接近于唯一值,那么只需要单建 idx_a 索引即可。
说明:存在非等号和等号混合时,在建索引时,请把等号条件的列前置。如:where c>? and d=? 那么即使 c 的区分度更高,也必须把 d 放在索引的最前列,即索引 idx_d_c。
(1) 宁滥勿缺。认为一个查询就需要建一个索引。
(2) 宁缺勿滥。认为索引会消耗空间、严重拖慢记录的更新以及行的新增速度。
(3) 抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。
怎样知道sql中用到索引没有?
执行sql语句时,前面加explain
id select_type table type posible_keys key key_len ref rows Extra
如果key有值表示用到了索引,key表示用到的索引名称
怎样知道索引是否被充分使用?
看key_len的值,
key_len的算法:4个参数
(1) 数据类型varchar+2 char+0 (2)字符集utf8=3字节 (3)是否为空 null+1 !null +0 (4)本身长度 例如varchar(50) 50表示50个中文或英文字符
例如:对date_str(50) not null 字段加了索引(复合索引),如果用到了该字段的索引,key_len=2+0+50*3=152
mysql并发的瓶颈?
一般300-700,硬件好的话最多1000,为什么,不知道
什么是数据库事务?ACID
原子性:事务不可分割,要嘛全部成功,要嘛全部失败
一致性:数据经过N多操作,数据是一致的,比如转账,总金额是一致的,一致性最关键
隔离性:各个事务之间之间不产生影响
持久性:事务执行成功进行落盘操作
隔离级别有哪些?
mysql事务测试
1.关闭自动提交
select @@autocommit; //查看事务是否自动提交
set autocommit=0; // 关闭自动提交
3.测试事务
read uncommitted 读未提交
命令:set session transaction isolation level read uncommitted;
read commited 读已提交
命令:set session transaction isolation level read committed;
repeatable read 可重复读
命令:set session transaction isolation level repeatable read;
searializible 序列化
脏读:在一个事务里,两次查询结果不一致,读到另一个事务未提交的数据
不可重复读:在一个事务里面,两次查询结果不一致,读到了另一个事务已提交的数据
幻读:在一个事务里,查询无数据,却insert主键失败(是另一个事务先commit insert导致)
测试方法:
打开A、B两个mysql客户端
1 A、B都关闭事务自动提交:set autocommit=0;
2 A、B都开始事务:start transaction;
3 A那边操作。。B那边操作。。。略
隔离级别 | 异常1 | 异常2 | 异常3 |
读未提交 | 脏读 | 不可重复读 | 幻读 |
读已提交 | 不可重复读 | 幻读 | |
可重复读 | 幻读 | ||
序列化 |
事务有哪些操作?
1.开始事务 2. 执行语句(失败回滚) 3.提交事务(失败回滚)