MySQL_icp

如果没有明确的说明,本文的存储引擎均是 InnoDB,版本:8.0

假设一个表如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE `dy_video_list` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`aweme_id` varchar(100) NOT NULL DEFAULT '',
`collect_count` int NOT NULL DEFAULT '0',
`comment_count` int NOT NULL DEFAULT '0',
`digg_count` int NOT NULL DEFAULT '0',
`share_count` int NOT NULL DEFAULT '0',
`tag` varchar(100) NOT NULL DEFAULT '',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `aweme_id_time` (`aweme_id`,`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

目前数据有 2700 +

索引下推(ICP)

阅读更多

慢查询排查以及优化

排查方式

SHOW PROCESSLIST

SHOW PROCESSLIST 只能查看到当前用户正在运行的线程,如果你是ROOT用户,那么是可以看到所有用户正在运行的线程
如果想看到其他用户的线程,则必须为此用户赋予 PROCESS 权限。

危害:

  1. 造成机器的 CPU 以及 IO 过高,影响到数据库实例。
  2. 阻塞 DDL 查询语句,会造成其他正常业务出现耗时过高。
  3. 会导致 mysql 出现 MDL 锁,影响到该机器上正常 SQL 的执行。
阅读更多

Redis中ziplist的实现二

添加 entry

ziplist 的添加过程大致如下:

  • 如果是一个新建的 ziplist,其中新增元素的时候,直接将 prevlen 设置为 0 即可

  • 如果是在中间位置新增,那么首先需要获取前一个 entry 的长度,因为后面的元素已经计算过了,因此直接拿来用即可

  • 如果是在尾部进行新增元素,那么需要计算其前一个元素的长度,因为 zlend 不会保存前一个最后一个尾节点的长度,因此需要在新增的时候计算

连锁更新

由于 ziplist 的设计,当前一个元素长度小于 254 的时候, prevlen 会以一个字节进行存储,但是当前一个元素大于 254 的时候,那么 prevlen 就会变成 5 个字节

阅读更多

Redis中ziplist的实现(一)

ziplist 是一个双向链表,但是不同于熟知的利用头指针和尾指针所形成的双向链表,ziplist 而是采用了一个特殊的实现

区别

普通的双向链表因为在每一个节点上都含有一个头节点和尾节点,所以在遍历的时候可以依次沿着每一个节点进行递归,而且在新增或者删除的时候,直接移动指针即可,并且每一个节点在内存中并不要求是连续的,只需要指针指向对应节点的内存地址即可。

但是 redis 使用的是内存,在内存满了的情况下就会造成 redis 的不可用,需要依据淘汰策略清理内存。

试想下如果 ziplist 像普通的双向链表一样,每一次新增一个 entry 都去申请一块新的内存,实现起来确实比较简单。

阅读更多

Redis中String的实现细节

String 是 Redis 中的基本数据结构之一,也是日常开发中使用最多的场景,例如秒杀扣库存,token缓存,详情缓存等,使用的频率还是比较高的,但是 Redis 中的 String 实现还是比较复杂的。

String 最底层的数据结构还是 char[],但是 Redis 在对数组进行封装的时候,做了一些细节上的优化

Redis 对象

在 Redis 中,每一个 Key 都可以称之为一个对象,Redis 包含了这个 Key 的类型,value 的内存地址,LRU 淘汰时间,引用计数等

1
2
3
4
5
6
7
struct RedisObject {
int4 type;
int 4 encoding;
int24 lru;
int32 refcount;
void *ptr;
}
阅读更多

Redis实现的分布式锁是完美的吗?

单实例

setnxRedis 官方提供的一个分布式原子性锁,它的实现利用了 Redis 在执行命令的时候是一个原子性操作,所以可以实现同一时间只有任务才能获取到锁。

当在同一个 redis 实例中进行加锁的操作的时候,如果加锁成功则会返回1,如果加锁失败的话,则是直接返回 0

1
2
127.0.0.1:6379> setnx 'redislock' 1
(integer) 1

如果此时另一个任务想进行加锁的话,则会返回0

阅读更多

mysql中count(*)和count(1)的区别

在进行旧的项目 review 的时候,我发现绝大多数的统计SQL都是基于 count(1) 来进行的,只有一少部分是基于 count(*),那么这两种写法到底有什么区别。

mysql中,常用的存储引擎有myisaminnodb,但是由于myisam只支持表级别锁,而且还不支持事物,所以在mysql的5.5版本之后就将默认的存储引擎调整为innodb

 
以下实验基于 Mysql8.0.1 来进行
 

首先这里准备了一个表.

阅读更多

MySql中int类型的简单总结

问题

首先问两个问题:

  1. int(1)和int(10)有什么区别。
  2. int(3)可以存储 10000 这个数字吗?
  3. int(11)可以用来存储手机号么?

本次的源代码以及测试的 Mysql 版本均为 8.0.17

解释

阅读更多

MySql的幻读(二)

定义

在InnoDB里面,是通过快照读来实现RCPR隔离级别的区分,因为在RC隔离级别下,每一次的select都是一个快照读,所以是可以读取到已经提交的数据,从而导致幻读。所以在RC隔离级别下,快照读和当前读都是可以出现幻读。

但是在PR的隔离级别下,由于快照读仅仅只生成一次,所以在PR级别下的快照读是无法出现幻读的,但是当前读确实可以出现幻读。

查看Mysql官方对于幻读的定义。

The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times.

阅读更多

MySql中的幻读(一)

什么是幻读

幻读表示的是在一个事物里面 同一个select语句,前后两次查询出来的结果是不相同的,需要注意的一点是,在InnoDB里面,幻读跟事物的隔离级别有关,更加准确的说是跟一个事物的快照和当前读有关

下面是在Mysql8.0.11版本下进行幻读的复现:

  • 引擎:InnoDB
  • 事物隔离级别:Read Commited

MVCC和快照读以及当前读

阅读更多