如果表是中id是连续自增,没有间断的,可以直接用主键id当作查询条件
select * from employees where id > 100000 limit 10;
由mysql中数据结构B+树,主键存储是有序的,所以使用 id > 100000 即走了索引表,又优化了查询速度
实际中,mysql内部索引优化器也会对我们写的sql进行优化,可能
EXPLAIN select * from table limit 100000,10;
也使用了索引,实际是因为mysql内部对sql进行了优化的原因
假设表table中name是索引字段
select * from table ORDER BY name limit 90000,5;
可以如下方式写sql
需要的结果与原 SQL 一致,执行的时间可能减少了一半以上
可以执行EXPLAIN操作试试
mysql的表关联常见有两种算法
一次一行循环地从第一张表(称为驱动表)中读取行,在这行数据中取到关联字段,根据关联字段在另一张表(被驱动表)里取出满足条件的行,然后取出两张表的结果合集。
上面sql的大致流程如下(假设t1是小表,t2是大表):
整个读取过程
join_buffer:MySQL对于table join的一个重要的优化手段,用来缓存这两类 JOIN 检索的一个 BUFFER 内存区域块。在"暴力"连接的时候可以极大提高join查询的效率。
每张使用 InnoDB 作为存储引擎的表都有一个特殊的索引称为聚集索引,它保存着每一行的数据,通常,聚集索引就是主键索引。为了得到更高效的查询、插入以及其他的数据库操作的性能,你必须理解 InnoDB 引擎是如何使用聚集索引来优化常见的查找和 DML 操作
如果你的表定义了一个主键,InnoDB 就使用它作为聚集索引。因此,尽可能的为你的表定义一个主键,如果实在没有一个数据列是唯一且非空的可以作为主键列,建议添加一个自动递增列作为主键列。
如果你的表既没有主键,又没有合适的唯一索引,InnoDB 内部会生成一个隐式聚集索引 —— GEN_CLUST_INDEX,该索引建立在由 rowid 组成的合成列上。数据行根据 InnoDB 分配的 rowid 排序,rowid 是一个 6 字节的字段,随着数据插入而单调递增。也就是说,数据行根据 rowid 排序实际上是根据插入顺序排序。
二级索引:
问题:
相比于叶子节点中存储行指针,二级索引存储主键值会占用更多的空间,那为什么要这样设计呢?
InnoDB在移动行时,无需维护二级索引,因为叶子节点中存储的是主键值,而不是指针。
那么InnoDB有了聚簇索引,为什么还要有二级索引呢?
,而,相比于聚簇索引,占用的空间要少。当我们需要为表建立多个索引时,如果都是聚簇索引,那将占用大量内存空间,所以InnoDB中主键所建立的是聚簇索引,而。
为什么一般情况下,我们建表的时候都会使用一个自增的id来作为我们的主键?
InnoDB中表中的数据是直接存储在主键聚簇索引的叶子节点中的,每插入一条记录,其实都是增加一个叶子节点,如果主键是顺序的,只需要把新增的一条记录存储在上一条记录的后面,当页达到最大填充因子的时候,下一跳记录就会写入新的页中,这种情况下,主键页就会近似于被顺序的记录填满。
把驱动表的数据读入到 join_buffer 中,然后扫描被驱动表,把被驱动表每一行取出来跟 join_buffer 中的数据做对比。
整个过程对表 t1 和 t2 都做了一次全表扫描,所以
因 join_buffer 里的数据是无序的,因此对表 t2 中的每一行,都需要做100次判断(t1表总数)因此
被驱动表的关联字段没索引或二级索引为什么要选择使用 BNL 算法而不使用 Nested-Loop Join 呢?
如果上面第二条sql使用 Nested-Loop Join,那么扫描行数为 100 * 10000(无索引全盘扫描) = 100万次,这个是磁盘扫描,效率非常低
实际开发中可以使用explain多试试
straight_join功能同join类似,但能让左边的表来驱动右边的表,能改表优化器对于联表查询的执行顺序。 比如:select * from t2 straight_join t1 on t2.a = t1.a; 代表制定mysql选着 t2 表作为驱动表。
,并不适用于left join,right join。(因为left join,right join已经代表指 定了表的执行顺序)尽可能让优化器去判断,因为大部分情况下mysql优化器是比人要聪明的。,因为部分情况下人为指定的执行顺序并不一定会比优化引擎要靠谱。
exists:将主查询A的数据,放到子查询B中做条件验证,根据验证结果(true或false)来决定主查询的数据是否保留
假设table表中有唯一索引、复合索引、单值索引中一种
执行结果key中发现除了无索引字段count(code),其余key中都是二级索引名
如果无二级索引,则count(1)、count(id)、count(*)都会使用PRIMARY查询总数
实际四个sql的执行计划一样,说明这四个sql执行效率应该差不多,区别在于,因为null在mysql底层B+树索引中存储没有跟节点,而是在最小叶子节点的最前端,所以不统计
实际性能基本性能区别不大
如果不需要很精准使用如下sql性能极高,获取sql中返回的rows对象,就是相似总数
借助redis做原子计数器
缺点:如果mysql 事物回滚,redis会导致计数不准。
增加一个计数表,每一行统计一个表的总数
当某个表发生事物问题统计表可以与之同步回滚(在同一个事物下)
有话要说...