mirror of https://github.com/dunwu/db-tutorial.git
📝 Writing docs.
parent
b2ac93c765
commit
8ebfa259a9
|
@ -11,44 +11,59 @@ tags:
|
|||
|
||||
# Redis 快速入门
|
||||
|
||||
## 概述
|
||||
<!-- TOC depthFrom:2 depthTo:3 -->
|
||||
|
||||
### 什么是 Redis
|
||||
- [1. 概述](#1-概述)
|
||||
- [1.1. 什么是 Redis](#11-什么是-redis)
|
||||
- [1.2. 为什么用 Redis](#12-为什么用-redis)
|
||||
- [2. 安装](#2-安装)
|
||||
- [2.1. Window 下安装](#21-window-下安装)
|
||||
- [2.2. Linux 下安装](#22-linux-下安装)
|
||||
- [2.3. Ubuntu 下安装](#23-ubuntu-下安装)
|
||||
- [2.4. 启动 Redis](#24-启动-redis)
|
||||
- [2.5. 查看 redis 是否启动?](#25-查看-redis-是否启动)
|
||||
- [3. Redis 命令](#3-redis-命令)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
||||
## 1. 概述
|
||||
|
||||
### 1.1. 什么是 Redis
|
||||
|
||||
Redis 是一个高性能的 key-value 数据库,也可用于缓存和消息代理。
|
||||
|
||||
### 为什么用 Redis
|
||||
### 1.2. 为什么用 Redis
|
||||
|
||||
与其它 key - value 数据库产品相比,具有以下优势:
|
||||
|
||||
- 支持数据持久化——可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
|
||||
|
||||
- 丰富的数据类型——Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
|
||||
- 丰富的数据类型——Redis 支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
|
||||
- 支持数据的备份——数据备份采用 master-slave 模式。
|
||||
- 性能极高——Redis 能读的速度是110000次/s,写的速度是81000次/s 。
|
||||
- 原子性——Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
|
||||
- 性能极高——Redis 能读的速度是 110000 次/s,写的速度是 81000 次/s 。
|
||||
- 原子性——Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过 MULTI 和 EXEC 指令包起来。
|
||||
|
||||
## 安装
|
||||
## 2. 安装
|
||||
|
||||
### Window 下安装
|
||||
### 2.1. Window 下安装
|
||||
|
||||
**下载地址:**<https://github.com/MSOpenTech/redis/releases>。
|
||||
|
||||
Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 **Redis-x64-xxx.zip**压缩包到 C 盘,解压后,将文件夹重新命名为 **redis**。
|
||||
|
||||
打开一个 **cmd** 窗口 使用cd命令切换目录到 **C:\redis** 运行 **redis-server.exe redis.windows.conf** 。
|
||||
打开一个 **cmd** 窗口 使用 cd 命令切换目录到 **C:\redis** 运行 **redis-server.exe redis.windows.conf** 。
|
||||
|
||||
如果想方便的话,可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的。输入之后,会显示如下界面:
|
||||
|
||||
这时候另启一个cmd窗口,原来的不要关闭,不然就无法访问服务端了。
|
||||
这时候另启一个 cmd 窗口,原来的不要关闭,不然就无法访问服务端了。
|
||||
|
||||
切换到redis目录下运行 **redis-cli.exe -h 127.0.0.1 -p 6379** 。
|
||||
切换到 redis 目录下运行 **redis-cli.exe -h 127.0.0.1 -p 6379** 。
|
||||
|
||||
设置键值对 **set myKey abc**
|
||||
|
||||
取出键值对 **get myKey**
|
||||
|
||||
### Linux 下安装
|
||||
### 2.2. Linux 下安装
|
||||
|
||||
**下载地址:**<http://redis.io/download>,下载最新文档版本。
|
||||
|
||||
|
@ -61,25 +76,25 @@ $ cd redis-2.8.17
|
|||
$ make
|
||||
```
|
||||
|
||||
make完后 redis-2.8.17目录下会出现编译后的redis服务程序redis-server,还有用于测试的客户端程序redis-cli,两个程序位于安装目录 src 目录下:
|
||||
make 完后 redis-2.8.17 目录下会出现编译后的 redis 服务程序 redis-server,还有用于测试的客户端程序 redis-cli,两个程序位于安装目录 src 目录下:
|
||||
|
||||
下面启动redis服务.
|
||||
下面启动 redis 服务.
|
||||
|
||||
```
|
||||
$ cd src
|
||||
$ ./redis-server
|
||||
```
|
||||
|
||||
注意这种方式启动redis 使用的是默认配置。也可以通过启动参数告诉redis使用指定配置文件使用下面命令启动。
|
||||
注意这种方式启动 redis 使用的是默认配置。也可以通过启动参数告诉 redis 使用指定配置文件使用下面命令启动。
|
||||
|
||||
```
|
||||
$ cd src
|
||||
$ ./redis-server redis.conf
|
||||
```
|
||||
|
||||
redis.conf是一个默认的配置文件。我们可以根据需要使用自己的配置文件。
|
||||
redis.conf 是一个默认的配置文件。我们可以根据需要使用自己的配置文件。
|
||||
|
||||
启动redis服务进程后,就可以使用测试客户端程序redis-cli和redis服务交互了。 比如:
|
||||
启动 redis 服务进程后,就可以使用测试客户端程序 redis-cli 和 redis 服务交互了。 比如:
|
||||
|
||||
```
|
||||
$ cd src
|
||||
|
@ -90,7 +105,7 @@ redis> get foo
|
|||
"bar"
|
||||
```
|
||||
|
||||
### Ubuntu 下安装
|
||||
### 2.3. Ubuntu 下安装
|
||||
|
||||
在 Ubuntu 系统安装 Redi 可以使用以下命令:
|
||||
|
||||
|
@ -99,13 +114,13 @@ $sudo apt-get update
|
|||
$sudo apt-get install redis-server
|
||||
```
|
||||
|
||||
### 启动 Redis
|
||||
### 2.4. 启动 Redis
|
||||
|
||||
```
|
||||
$ redis-server
|
||||
```
|
||||
|
||||
### 查看 redis 是否启动?
|
||||
### 2.5. 查看 redis 是否启动?
|
||||
|
||||
```
|
||||
$ redis-cli
|
||||
|
@ -124,9 +139,9 @@ redis 127.0.0.1:6379> ping
|
|||
PONG
|
||||
```
|
||||
|
||||
以上说明我们已经成功安装了redis。
|
||||
以上说明我们已经成功安装了 redis。
|
||||
|
||||
## Redis 命令
|
||||
## 3. Redis 命令
|
||||
|
||||
Redis 命令用于在 redis 服务上执行操作。
|
||||
|
||||
|
@ -156,128 +171,3 @@ PONG
|
|||
```
|
||||
|
||||
更多命令行可以参考:[Redis 官方命令行字典](https://redis.io/commands)
|
||||
|
||||
## 数据类型
|
||||
|
||||
### String
|
||||
|
||||
> string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
|
||||
>
|
||||
> string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如图片或者序列化的对象 。
|
||||
>
|
||||
> string 类型是 Redis 最基本的数据类型,一个键最大能存储 512MB。
|
||||
|
||||
**实例**
|
||||
|
||||
```sh
|
||||
redis 127.0.0.1:6379> set name "abc"
|
||||
OK
|
||||
redis 127.0.0.1:6379> get name
|
||||
"abc"
|
||||
```
|
||||
|
||||
### Hash
|
||||
|
||||
> hash 是一个键值对集合。
|
||||
>
|
||||
> hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
|
||||
|
||||
**实例**
|
||||
|
||||
```sh
|
||||
127.0.0.1:6379> HMSET user:1 username root password root points 200
|
||||
OK
|
||||
127.0.0.1:6379> HGETALL user:1
|
||||
1) "username"
|
||||
2) "root"
|
||||
3) "password"
|
||||
4) "root"
|
||||
5) "points"
|
||||
6) "200"
|
||||
```
|
||||
|
||||
以上实例中 hash 数据类型存储了包含用户脚本信息的用户对象。 实例中我们使用了 Redis **HMSET, HGETALL** 命令,**user:1**为键值。
|
||||
|
||||
### List
|
||||
|
||||
> List 是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
|
||||
|
||||
**实例**
|
||||
|
||||
```sh
|
||||
127.0.0.1:6379> lpush mylist redis
|
||||
(integer) 1
|
||||
127.0.0.1:6379> lpush mylist mongodb
|
||||
(integer) 2
|
||||
127.0.0.1:6379> lpush mylist hbase
|
||||
(integer) 3
|
||||
127.0.0.1:6379> lrange mylist 0 10
|
||||
1) "hbase"
|
||||
2) "mongodb"
|
||||
3) "redis"
|
||||
127.0.0.1:6379>
|
||||
```
|
||||
|
||||
### Set
|
||||
|
||||
> Redis 的 Set 是 string 类型的无序集合。
|
||||
>
|
||||
> 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
|
||||
|
||||
**实例**
|
||||
|
||||
```sh
|
||||
127.0.0.1:6379> sadd colorset red
|
||||
(integer) 1
|
||||
127.0.0.1:6379> sadd colorset red
|
||||
(integer) 0
|
||||
127.0.0.1:6379> sadd colorset yellow
|
||||
(integer) 1
|
||||
127.0.0.1:6379> sadd colorset blue
|
||||
(integer) 1
|
||||
127.0.0.1:6379> smembers colorset
|
||||
1) "yellow"
|
||||
2) "red"
|
||||
3) "blue"
|
||||
127.0.0.1:6379> srem colorset red
|
||||
(integer) 1
|
||||
127.0.0.1:6379> smembers colorset
|
||||
1) "yellow"
|
||||
2) "blue"
|
||||
```
|
||||
|
||||
### Sorted Set
|
||||
|
||||
> Redis zset 和 set 一样也是 string 类型元素的集合,且不允许重复的成员。
|
||||
>
|
||||
> 不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
|
||||
>
|
||||
> zset 的成员是唯一的,但分数(score)却可以重复。
|
||||
|
||||
**实例**
|
||||
|
||||
```sh
|
||||
127.0.0.1:6379> zadd week 5 Friday
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zadd week 6 Saturday
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zadd week 1 Monday
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zadd week 2 Tuesday
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zadd week 3 Wednesday
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zadd week 4 Thursday
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zadd week 7 Sunday
|
||||
(integer) 1
|
||||
127.0.0.1:6379> zrangebyscore week 0 1000
|
||||
1) "Monday"
|
||||
2) "Tuesday"
|
||||
3) "Wednesday"
|
||||
4) "Thursday"
|
||||
5) "Friday"
|
||||
6) "Saturday"
|
||||
7) "Sunday"
|
||||
```
|
||||
|
||||
|
|
|
@ -11,30 +11,47 @@ tags:
|
|||
|
||||
# Redis
|
||||
|
||||
<!-- TOC depthFrom:2 depthTo:2 -->
|
||||
<!-- TOC depthFrom:2 depthTo:3 -->
|
||||
|
||||
- [概述](#概述)
|
||||
- [数据类型](#数据类型)
|
||||
- [使用场景](#使用场景)
|
||||
- [Redis 与 Memcached](#redis-与-memcached)
|
||||
- [Redis 管道](#redis-管道)
|
||||
- [键的过期时间](#键的过期时间)
|
||||
- [数据淘汰策略](#数据淘汰策略)
|
||||
- [持久化](#持久化)
|
||||
- [发布与订阅](#发布与订阅)
|
||||
- [事务](#事务)
|
||||
- [事件](#事件)
|
||||
- [复制](#复制)
|
||||
- [Sentinel](#sentinel)
|
||||
- [分片](#分片)
|
||||
- [Redis Client](#redis-client)
|
||||
- [资料](#资料)
|
||||
- [1. 概述](#1-概述)
|
||||
- [1.1. Redis 简介](#11-redis-简介)
|
||||
- [1.2. Redis 的优势](#12-redis-的优势)
|
||||
- [1.3. Redis 与 Memcached](#13-redis-与-memcached)
|
||||
- [2. 数据类型](#2-数据类型)
|
||||
- [2.1. STRING](#21-string)
|
||||
- [2.2. LIST](#22-list)
|
||||
- [2.3. SET](#23-set)
|
||||
- [2.4. HASH](#24-hash)
|
||||
- [2.5. ZSET](#25-zset)
|
||||
- [3. 使用场景](#3-使用场景)
|
||||
- [4. Redis 管道](#4-redis-管道)
|
||||
- [5. 键的过期时间](#5-键的过期时间)
|
||||
- [6. 数据淘汰策略](#6-数据淘汰策略)
|
||||
- [7. 持久化](#7-持久化)
|
||||
- [7.1. 快照持久化](#71-快照持久化)
|
||||
- [7.2. AOF 持久化](#72-aof-持久化)
|
||||
- [8. 发布与订阅](#8-发布与订阅)
|
||||
- [9. 事务](#9-事务)
|
||||
- [9.1. EXEC](#91-exec)
|
||||
- [9.2. MULTI](#92-multi)
|
||||
- [9.3. DISCARD](#93-discard)
|
||||
- [9.4. WATCH](#94-watch)
|
||||
- [10. 事件](#10-事件)
|
||||
- [10.1. 文件事件](#101-文件事件)
|
||||
- [10.2. 时间事件](#102-时间事件)
|
||||
- [10.3. 事件的调度与执行](#103-事件的调度与执行)
|
||||
- [11. 集群](#11-集群)
|
||||
- [11.1. 复制](#111-复制)
|
||||
- [11.2. 哨兵](#112-哨兵)
|
||||
- [11.3. 分片](#113-分片)
|
||||
- [12. Redis Client](#12-redis-client)
|
||||
- [13. 资料](#13-资料)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
||||
## 概述
|
||||
## 1. 概述
|
||||
|
||||
### Redis 简介
|
||||
### 1.1. Redis 简介
|
||||
|
||||
Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以存储键和五种不同类型的值之间的映射。
|
||||
|
||||
|
@ -42,7 +59,7 @@ Redis 是速度非常快的非关系型(NoSQL)内存键值数据库,可以
|
|||
|
||||
Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,使用复制来扩展读性能,使用分片来扩展写性能。
|
||||
|
||||
### Redis 的优势
|
||||
### 1.2. Redis 的优势
|
||||
|
||||
- 性能极高 – Redis 能读的速度是 110000 次/s,写的速度是 81000 次/s。
|
||||
- 丰富的数据类型 - 支持字符串、列表、集合、有序集合、散列表。
|
||||
|
@ -51,7 +68,31 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
|
|||
- 备份 - Redis 支持数据的备份,即 master-slave 模式的数据备份。
|
||||
- 丰富的特性 - Redis 还支持发布订阅, 通知, key 过期等等特性。
|
||||
|
||||
## 数据类型
|
||||
### 1.3. Redis 与 Memcached
|
||||
|
||||
Redis 与 Memcached 因为都可以用于缓存,所以常常被拿来做比较,二者主要有以下区别:
|
||||
|
||||
**数据类型**
|
||||
|
||||
- Memcached 仅支持字符串类型;
|
||||
- 而 Redis 支持五种不同种类的数据类型,使得它可以更灵活地解决问题。
|
||||
|
||||
**数据持久化**
|
||||
|
||||
- Memcached 不支持持久化;
|
||||
- Redis 支持两种持久化策略:RDB 快照和 AOF 日志。
|
||||
|
||||
**分布式**
|
||||
|
||||
- Memcached 不支持分布式,只能通过在客户端使用像一致性哈希这样的分布式算法来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。
|
||||
- Redis Cluster 实现了分布式的支持。
|
||||
|
||||
**内存管理机制**
|
||||
|
||||
- Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题,但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。
|
||||
- 在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘。而 Memcached 的数据则会一直在内存中。
|
||||
|
||||
## 2. 数据类型
|
||||
|
||||
| 数据类型 | 可以存储的值 | 操作 |
|
||||
| -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
|
@ -63,7 +104,7 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
|
|||
|
||||
> [What Redis data structures look like](https://redislabs.com/ebook/part-1-getting-started/chapter-1-getting-to-know-redis/1-2-what-redis-data-structures-look-like/)
|
||||
|
||||
### STRING
|
||||
### 2.1. STRING
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/dunwu/database/master/images/redis/redis-datatype-string.png" width="400"/>
|
||||
|
@ -90,7 +131,7 @@ OK
|
|||
(nil)
|
||||
```
|
||||
|
||||
### LIST
|
||||
### 2.2. LIST
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/dunwu/database/master/images/redis/redis-datatype-list.png" width="400"/>
|
||||
|
@ -127,7 +168,7 @@ OK
|
|||
2) "item3"
|
||||
```
|
||||
|
||||
### SET
|
||||
### 2.3. SET
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/dunwu/database/master/images/redis/redis-datatype-set.png" width="400"/>
|
||||
|
@ -174,7 +215,7 @@ OK
|
|||
2) "item1"
|
||||
```
|
||||
|
||||
### HASH
|
||||
### 2.4. HASH
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/dunwu/database/master/images/redis/redis-datatype-hash.png" width="400"/>
|
||||
|
@ -225,7 +266,7 @@ OK
|
|||
127.0.0.1:6379>
|
||||
```
|
||||
|
||||
### ZSET
|
||||
### 2.5. ZSET
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/dunwu/database/master/images/redis/redis-datatype-zset.png" width="400"/>
|
||||
|
@ -277,7 +318,7 @@ OK
|
|||
4) "2"
|
||||
```
|
||||
|
||||
## 使用场景
|
||||
## 3. 使用场景
|
||||
|
||||
- **缓存** - 将热点数据放到内存中,设置内存的最大使用量以及过期淘汰策略来保证缓存的命中率。
|
||||
- **计数器** - Redis 这种内存数据库能支持计数器频繁的读写操作。
|
||||
|
@ -289,31 +330,7 @@ OK
|
|||
- **分布式 Session** - 多个应用服务器的 Session 都存储到 Redis 中来保证 Session 的一致性。
|
||||
- **分布式锁** - 除了可以使用 SETNX 实现分布式锁之外,还可以使用官方提供的 RedLock 分布式锁实现。
|
||||
|
||||
## Redis 与 Memcached
|
||||
|
||||
两者都是非关系型内存键值数据库。有以下主要不同:
|
||||
|
||||
**数据类型**
|
||||
|
||||
- Memcached 仅支持字符串类型;
|
||||
- 而 Redis 支持五种不同种类的数据类型,使得它可以更灵活地解决问题。
|
||||
|
||||
**数据持久化**
|
||||
|
||||
- Memcached 不支持持久化;
|
||||
- Redis 支持两种持久化策略:RDB 快照和 AOF 日志。
|
||||
|
||||
**分布式**
|
||||
|
||||
- Memcached 不支持分布式,只能通过在客户端使用像一致性哈希这样的分布式算法来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。
|
||||
- Redis Cluster 实现了分布式的支持。
|
||||
|
||||
**内存管理机制**
|
||||
|
||||
- Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题,但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。
|
||||
- 在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘。而 Memcached 的数据则会一直在内存中。
|
||||
|
||||
## Redis 管道
|
||||
## 4. Redis 管道
|
||||
|
||||
Redis 是一种基于 C/S 模型以及请求/响应协议的 TCP 服务。
|
||||
|
||||
|
@ -321,7 +338,7 @@ Redis 支持管道技术。管道技术允许请求以异步方式发送,即
|
|||
|
||||
使用管道发送命令时,服务器将被迫回复一个队列答复,占用很多内存。所以,如果你需要发送大量的命令,最好是把他们按照合理数量分批次的处理。
|
||||
|
||||
## 键的过期时间
|
||||
## 5. 键的过期时间
|
||||
|
||||
Redis 可以为每个键设置过期时间,当键过期时,会自动删除该键。
|
||||
|
||||
|
@ -347,7 +364,7 @@ redis> TTL mykey
|
|||
redis>
|
||||
```
|
||||
|
||||
## 数据淘汰策略
|
||||
## 6. 数据淘汰策略
|
||||
|
||||
可以设置内存最大使用量,当内存使用量超过时施行淘汰策略,具体有 6 种淘汰策略。
|
||||
|
||||
|
@ -364,11 +381,11 @@ redis>
|
|||
|
||||
作为内存数据库,出于对性能和内存消耗的考虑,Redis 的淘汰算法(LRU、TTL)实际实现上并非针对所有 key,而是抽样一小部分 key 从中选出被淘汰 key,抽样数量可通过 maxmemory-samples 配置。
|
||||
|
||||
## 持久化
|
||||
## 7. 持久化
|
||||
|
||||
Redis 是内存型数据库,为了保证数据在断电后不会丢失,需要将内存中的数据持久化到硬盘上。
|
||||
|
||||
### 快照持久化
|
||||
### 7.1. 快照持久化
|
||||
|
||||
将某个时间点的所有数据都存放到硬盘上。
|
||||
|
||||
|
@ -378,7 +395,7 @@ Redis 是内存型数据库,为了保证数据在断电后不会丢失,需
|
|||
|
||||
如果数据量很大,保存快照的时间会很长。
|
||||
|
||||
### AOF 持久化
|
||||
### 7.2. AOF 持久化
|
||||
|
||||
将写命令添加到 AOF 文件(Append Only File)的末尾。
|
||||
|
||||
|
@ -398,7 +415,7 @@ Redis 是内存型数据库,为了保证数据在断电后不会丢失,需
|
|||
|
||||
随着服务器写请求的增多,AOF 文件会越来越大。Redis 提供了一种将 AOF 重写的特性,能够去除 AOF 文件中的冗余写命令。
|
||||
|
||||
## 发布与订阅
|
||||
## 8. 发布与订阅
|
||||
|
||||
订阅者订阅了频道之后,发布者向频道发送字符串消息会被所有订阅者接收到。
|
||||
|
||||
|
@ -409,7 +426,7 @@ Redis 是内存型数据库,为了保证数据在断电后不会丢失,需
|
|||
- 观察者模式中,观察者和主题都知道对方的存在;而在发布与订阅模式中,发布者与订阅者不知道对方的存在,它们之间通过频道进行通信。
|
||||
- 观察者模式是同步的,当事件触发时,主题会去调用观察者的方法;而发布与订阅模式是异步的;
|
||||
|
||||
## 事务
|
||||
## 9. 事务
|
||||
|
||||
MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。
|
||||
|
||||
|
@ -418,18 +435,18 @@ MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。
|
|||
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
|
||||
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
|
||||
|
||||
### EXEC
|
||||
### 9.1. EXEC
|
||||
|
||||
EXEC 命令负责触发并执行事务中的所有命令:
|
||||
|
||||
- 如果客户端在使用 MULTI 开启了一个事务之后,却因为断线而没有成功执行 EXEC ,那么事务中的所有命令都不会被执行。
|
||||
- 另一方面,如果客户端成功在开启事务之后执行 EXEC ,那么事务中的所有命令都会被执行。
|
||||
|
||||
### MULTI
|
||||
### 9.2. MULTI
|
||||
|
||||
MULTI 命令用于开启一个事务,它总是返回 OK 。 MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC 命令被调用时, 所有队列中的命令才会被执行。
|
||||
|
||||
### DISCARD
|
||||
### 9.3. DISCARD
|
||||
|
||||
当执行 DISCARD 命令时, 事务会被放弃, 事务队列会被清空, 并且客户端会从事务状态中退出。
|
||||
|
||||
|
@ -448,7 +465,7 @@ OK
|
|||
"1"
|
||||
```
|
||||
|
||||
### WATCH
|
||||
### 9.4. WATCH
|
||||
|
||||
WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。
|
||||
|
||||
|
@ -484,17 +501,17 @@ OK
|
|||
|
||||
使用无参数的 UNWATCH 命令可以手动取消对所有键的监视。 对于一些需要改动多个键的事务, 有时候程序需要同时对多个键进行加锁, 然后检查这些键的当前值是否符合程序的要求。 当值达不到要求时, 就可以使用 UNWATCH 命令来取消目前对键的监视, 中途放弃这个事务, 并等待事务的下次尝试。
|
||||
|
||||
## 事件
|
||||
## 10. 事件
|
||||
|
||||
Redis 服务器是一个事件驱动程序。
|
||||
|
||||
### 文件事件
|
||||
### 10.1. 文件事件
|
||||
|
||||
服务器通过套接字与客户端或者其它服务器进行通信,文件事件就是对套接字操作的抽象。
|
||||
|
||||
Redis 基于 Reactor 模式开发了自己的网络时间处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的时间传送给文件事件分派器,分派器会根据套接字产生的事件类型调用响应的时间处理器。
|
||||
|
||||
### 时间事件
|
||||
### 10.2. 时间事件
|
||||
|
||||
服务器有一些操作需要在给定的时间点执行,时间事件是对这类定时操作的抽象。
|
||||
|
||||
|
@ -505,7 +522,7 @@ Redis 基于 Reactor 模式开发了自己的网络时间处理器,使用 I/O
|
|||
|
||||
Redis 将所有时间事件都放在一个无序链表中,通过遍历整个链表查找出已到达的时间事件,并调用响应的事件处理器。
|
||||
|
||||
### 事件的调度与执行
|
||||
### 10.3. 事件的调度与执行
|
||||
|
||||
服务器需要不断监听文件事件的套接字才能得到待处理的文件事件,但是不能监听太久,否则时间事件无法在规定的时间内执行,因此监听时间应该根据距离现在最近的时间事件来决定。
|
||||
|
||||
|
@ -555,13 +572,15 @@ def main():
|
|||
|
||||
从事件处理的角度来看,服务器运行流程如下:
|
||||
|
||||
## 复制
|
||||
## 11. 集群
|
||||
|
||||
### 11.1. 复制
|
||||
|
||||
通过使用 slaveof host port 命令来让一个服务器成为另一个服务器的从服务器。
|
||||
|
||||
一个从服务器只能有一个主服务器,并且不支持主主复制。
|
||||
|
||||
### 连接过程
|
||||
#### 12.1. 连接过程
|
||||
|
||||
1. 主服务器创建快照文件,发送给从服务器,并在发送期间使用缓冲区记录执行的写命令。快照文件发送完毕之后,开始向从服务器发送存储在缓冲区中的写命令;
|
||||
|
||||
|
@ -569,15 +588,15 @@ def main():
|
|||
|
||||
3. 主服务器每执行一次写命令,就向从服务器发送相同的写命令。
|
||||
|
||||
### 主从链
|
||||
#### 12.2. 主从链
|
||||
|
||||
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
|
||||
|
||||
## Sentinel
|
||||
### 11.2. 哨兵
|
||||
|
||||
Sentinel(哨兵)可以监听主服务器,并在主服务器进入下线状态时,自动从从服务器中选举出新的主服务器。
|
||||
|
||||
## 分片
|
||||
### 11.3. 分片
|
||||
|
||||
分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,也可以从多台机器里面获取数据,这种方法在解决某些问题时可以获得线性级别的性能提升。
|
||||
|
||||
|
@ -589,7 +608,7 @@ Sentinel(哨兵)可以监听主服务器,并在主服务器进入下线状
|
|||
- 代理分片:将客户端请求发送到代理上,由代理转发请求到正确的节点上。
|
||||
- 服务器分片:Redis Cluster。
|
||||
|
||||
## Redis Client
|
||||
## 12. Redis Client
|
||||
|
||||
Redis 社区中有多种编程语言的客户端,可以在这里查找合适的客户端:https://redis.io/clients
|
||||
|
||||
|
@ -599,7 +618,7 @@ redis 官方推荐的 Java Redis Client:
|
|||
- [redisson](https://github.com/redisson/redisson)
|
||||
- [lettuce](https://github.com/lettuce-io/lettuce-core)
|
||||
|
||||
## 资料
|
||||
## 13. 资料
|
||||
|
||||
- [Redis 官网](https://redis.io/)
|
||||
- [awesome-redis](https://github.com/JamzyWang/awesome-redis)
|
||||
|
|
68
docs/sql.md
68
docs/sql.md
|
@ -16,27 +16,27 @@ tags:
|
|||
|
||||
<!-- TOC depthFrom:2 depthTo:2 -->
|
||||
|
||||
- [概念](#概念)
|
||||
- [SQL 基础](#sql-基础)
|
||||
- [增删改查](#增删改查)
|
||||
- [过滤](#过滤)
|
||||
- [函数](#函数)
|
||||
- [排序和分组](#排序和分组)
|
||||
- [子查询](#子查询)
|
||||
- [连接和组合](#连接和组合)
|
||||
- [数据定义](#数据定义)
|
||||
- [约束](#约束)
|
||||
- [事务处理](#事务处理)
|
||||
- [权限控制](#权限控制)
|
||||
- [存储过程](#存储过程)
|
||||
- [游标](#游标)
|
||||
- [触发器](#触发器)
|
||||
- [知识点小结](#知识点小结)
|
||||
- [参考资料](#参考资料)
|
||||
- [1. 概念](#1-概念)
|
||||
- [2. SQL 基础](#2-sql-基础)
|
||||
- [3. 增删改查](#3-增删改查)
|
||||
- [4. 过滤](#4-过滤)
|
||||
- [5. 函数](#5-函数)
|
||||
- [6. 排序和分组](#6-排序和分组)
|
||||
- [7. 子查询](#7-子查询)
|
||||
- [8. 连接和组合](#8-连接和组合)
|
||||
- [9. 数据定义](#9-数据定义)
|
||||
- [10. 约束](#10-约束)
|
||||
- [11. 事务处理](#11-事务处理)
|
||||
- [12. 权限控制](#12-权限控制)
|
||||
- [13. 存储过程](#13-存储过程)
|
||||
- [14. 游标](#14-游标)
|
||||
- [15. 触发器](#15-触发器)
|
||||
- [16. 知识点小结](#16-知识点小结)
|
||||
- [17. 参考资料](#17-参考资料)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
||||
## 概念
|
||||
## 1. 概念
|
||||
|
||||
- 数据库(database):保存有组织的数据的容器(通常是一个文件或一组文件)。
|
||||
- 数据表(table):某种特定类型数据的结构化清单。
|
||||
|
@ -44,7 +44,7 @@ tags:
|
|||
- 列(column):表中的一个字段。所有表都是由一个或多个列组成的。
|
||||
- 行(row):表中的一个记录。
|
||||
|
||||
## SQL 基础
|
||||
## 2. SQL 基础
|
||||
|
||||
> SQL(Structured Query Language),标准 SQL 由 ANSI 标准委员会管理,从而称为 ANSI SQL。各个 DBMS 都有自己的实现,如 PL/SQL、Transact-SQL 等。
|
||||
|
||||
|
@ -133,7 +133,7 @@ DCL 以控制用户的访问权限为主,因此其指令作法并不复杂,
|
|||
|
||||
TCL 的核心指令是 `COMMIT`、`ROLLBACK`。
|
||||
|
||||
## 增删改查
|
||||
## 3. 增删改查
|
||||
|
||||
### 插入数据
|
||||
|
||||
|
@ -251,7 +251,7 @@ SELECT * FROM mytable LIMIT 0, 5;
|
|||
SELECT * FROM mytable LIMIT 2, 3;
|
||||
```
|
||||
|
||||
## 过滤
|
||||
## 4. 过滤
|
||||
|
||||
### WHERE
|
||||
|
||||
|
@ -388,7 +388,7 @@ FROM products
|
|||
WHERE prod_name LIKE '__ inch teddy bear';
|
||||
```
|
||||
|
||||
## 函数
|
||||
## 5. 函数
|
||||
|
||||
各个 DBMS 的函数都是不相同的,因此不可移植。
|
||||
|
||||
|
@ -476,7 +476,7 @@ SELECT AVG(DISTINCT col1) AS avg_col
|
|||
FROM mytable
|
||||
```
|
||||
|
||||
## 排序和分组
|
||||
## 6. 排序和分组
|
||||
|
||||
### ORDER BY
|
||||
|
||||
|
@ -546,7 +546,7 @@ GROUP BY cust_name
|
|||
HAVING COUNT(*) >= 1;
|
||||
```
|
||||
|
||||
## 子查询
|
||||
## 7. 子查询
|
||||
|
||||
### 要点
|
||||
|
||||
|
@ -575,7 +575,7 @@ WHERE cust_id IN (SELECT cust_id
|
|||
WHERE prod_id = 'RGAN01'));
|
||||
```
|
||||
|
||||
## 连接和组合
|
||||
## 8. 连接和组合
|
||||
|
||||
### 连接(JOIN)
|
||||
|
||||
|
@ -680,7 +680,7 @@ WHERE cust_name = 'Fun4All';
|
|||
- `JOIN` 中连接表的列可能不同,但在 `UNION` 中,所有查询的列数和列顺序必须相同。
|
||||
- `UNION` 将查询之后的行放在一起(垂直放置),但 `JOIN` 将查询之后的列放在一起(水平放置),即它构成一个笛卡尔积。
|
||||
|
||||
## 数据定义
|
||||
## 9. 数据定义
|
||||
|
||||
> DDL 的主要功能是定义数据库对象(如:数据库、数据表、视图、索引等)。
|
||||
|
||||
|
@ -838,7 +838,7 @@ CREATE UNIQUE INDEX user_index
|
|||
ON user (id);
|
||||
```
|
||||
|
||||
## 约束
|
||||
## 10. 约束
|
||||
|
||||
### 要点
|
||||
|
||||
|
@ -868,7 +868,7 @@ CREATE TABLE Users (
|
|||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
|
||||
```
|
||||
|
||||
## 事务处理
|
||||
## 11. 事务处理
|
||||
|
||||
### 要点
|
||||
|
||||
|
@ -907,7 +907,7 @@ ROLLBACK TO updateA;
|
|||
COMMIT;
|
||||
```
|
||||
|
||||
## 权限控制
|
||||
## 12. 权限控制
|
||||
|
||||
### 要点
|
||||
|
||||
|
@ -970,7 +970,7 @@ REVOKE SELECT, INSERT ON *.* FROM myuser;
|
|||
SET PASSWORD FOR myuser = 'mypass';
|
||||
```
|
||||
|
||||
## 存储过程
|
||||
## 13. 存储过程
|
||||
|
||||
### 要点
|
||||
|
||||
|
@ -1015,7 +1015,7 @@ call proc_adder(2,@b,@s);
|
|||
select @s as sum;
|
||||
```
|
||||
|
||||
## 游标
|
||||
## 14. 游标
|
||||
|
||||
### 要点
|
||||
|
||||
|
@ -1066,7 +1066,7 @@ DELIMITER ;
|
|||
call getTotal();
|
||||
```
|
||||
|
||||
## 触发器
|
||||
## 15. 触发器
|
||||
|
||||
### 示例
|
||||
|
||||
|
@ -1141,13 +1141,13 @@ DROP TRIGGER IF EXISTS trigger_insert_user;
|
|||
- 在 `DELETE` 型触发器中,`OLD` 用来表示将要或已经被删除的原数据;
|
||||
- 使用方法: `NEW.columnName` (columnName 为相应数据表某一列名)
|
||||
|
||||
## 知识点小结
|
||||
## 16. 知识点小结
|
||||
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/dunwu/database/master/images/mysql/mysql.png" alt="mysql" width="1024">
|
||||
</p>
|
||||
|
||||
## 参考资料
|
||||
## 17. 参考资料
|
||||
|
||||
- BenForta. SQL 必知必会 [M]. 人民邮电出版社, 2013.
|
||||
- [『浅入深出』MySQL 中事务的实现](https://draveness.me/mysql-transaction)
|
||||
|
|
146
docs/数据库优化.md
146
docs/数据库优化.md
|
@ -1,146 +0,0 @@
|
|||
# 数据库优化
|
||||
|
||||
> 本文的数据库优化手段主要针对关系型数据库,不适合 key-value 数据库、内存数据库。
|
||||
|
||||
<!-- TOC depthFrom:2 depthTo:3 -->
|
||||
|
||||
- [查询注意事项](#查询注意事项)
|
||||
- [合理创建索引](#合理创建索引)
|
||||
- [不适宜创建索引的情况](#不适宜创建索引的情况)
|
||||
- [索引的注意事项](#索引的注意事项)
|
||||
- [数据类型](#数据类型)
|
||||
- [临时表](#临时表)
|
||||
- [游标](#游标)
|
||||
- [资料](#资料)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
||||
|
||||
## 查询注意事项
|
||||
|
||||
(1)不要写一些没有意义的查询,如需要生成一个空表结构:
|
||||
|
||||
```sql
|
||||
select col1,col2 into #t from t where 1=0
|
||||
```
|
||||
|
||||
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
|
||||
|
||||
```sql
|
||||
create table #t(...)
|
||||
```
|
||||
|
||||
(2)很多时候用 exists 代替 in 是一个好的选择:
|
||||
|
||||
```sql
|
||||
select num from a where num in(select num from b)
|
||||
```
|
||||
|
||||
用下面的语句替换:
|
||||
|
||||
```sql
|
||||
select num from a where exists(select 1 from b where num=a.num)
|
||||
```
|
||||
|
||||
(3)任何地方都不要使用 select \* from t ,用具体的字段列表代替“\*”,不要返回用不到的任何字段。
|
||||
|
||||
(4)尽量避免大事务操作,提高系统并发能力。
|
||||
|
||||
(5)尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
|
||||
|
||||
## 合理创建索引
|
||||
|
||||
对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
|
||||
|
||||
### 不适宜创建索引的情况
|
||||
|
||||
(1)应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
|
||||
|
||||
```sql
|
||||
select id from t where num is null
|
||||
```
|
||||
|
||||
可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询:
|
||||
|
||||
```sql
|
||||
select id from t where num=0
|
||||
```
|
||||
|
||||
(2)应尽量避免在 where 子句中使用 != 或 <> 操作符,否则 sql 引擎将放弃使用索引而进行全表扫描。
|
||||
|
||||
(3)应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
|
||||
|
||||
```sql
|
||||
select id from t where num=10 or num=20
|
||||
```
|
||||
|
||||
可以这样查询:
|
||||
|
||||
```sql
|
||||
select id from t where num=10
|
||||
union all
|
||||
select id from t where num=20
|
||||
```
|
||||
|
||||
(4)in 和 not in 也要慎用,否则会导致全表扫描,如:
|
||||
|
||||
```sql
|
||||
select id from t where num in(1,2,3)
|
||||
```
|
||||
|
||||
对于连续的数值,能用 between 就不要用 in 了:
|
||||
|
||||
```sql
|
||||
select id from t where num between 1 and 3
|
||||
```
|
||||
|
||||
(5)模糊查询的 Like 语法也将导致全表扫描:
|
||||
|
||||
```sql
|
||||
select id from t where name like '%abc%'
|
||||
```
|
||||
|
||||
(6)应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
|
||||
|
||||
```sql
|
||||
select id from t where num/2=100
|
||||
```
|
||||
|
||||
应改为:
|
||||
|
||||
```sql
|
||||
select id from t where num=100\*2
|
||||
```
|
||||
|
||||
(7)应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:`select id from t where substring(name,1,3)='abc'--name` 以 abc 开头的 id
|
||||
应改为: `select id from t where name like 'abc%'`
|
||||
|
||||
(8)不要在 where 子句中的 `=` 左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
|
||||
|
||||
### 索引的注意事项
|
||||
|
||||
1. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
|
||||
2. 并不是所有索引对查询都有效,SQL 是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL 查询可能不会去利用索引,如一表中有字段 sex,male、female 几乎各一半,那么即使在 sex 上建了索引也对查询效率起不了作用。
|
||||
3. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过 6 个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
|
||||
|
||||
## 数据类型
|
||||
|
||||
1. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
|
||||
2. 尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
|
||||
|
||||
## 临时表
|
||||
|
||||
1. 避免频繁创建和删除临时表,以减少系统表资源的消耗。
|
||||
2. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
|
||||
3. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先 create table,然后 insert。
|
||||
4. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
|
||||
|
||||
## 游标
|
||||
|
||||
1. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过 1 万行,那么就应该考虑改写。
|
||||
2. 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
|
||||
3. 与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。
|
||||
|
||||
## 资料
|
||||
|
||||
- [数据库 SQL 优化大总结之百万级数据库优化方案](https://blog.csdn.net/zhushuai1221/article/details/51740846)
|
Loading…
Reference in New Issue