搜尋
首頁資料庫Redis一文搞懂redis的bitmap

這篇文章為大家帶來了關於Redis的相關知識,其中主要介紹了bitmap問題,Redis 為我們提供了點陣圖這個資料結構,點陣圖資料結構其實不是一個全新的玩意,我們可以簡單的認為就是個數組,只是裡面的內容只能為0或1而已,希望對大家有幫助。

一文搞懂redis的bitmap

推薦學習:Redis影片教學

#1.點陣圖簡介

#如果我們需要記錄某一使用者在一年中每天是否有登入我們的系統這項需求該如何完成呢?如果使用KV存儲,每個用戶需要記錄365個,當用戶量上億時,這所需的存儲空間是驚人的。

Redis 為我們提供了位圖這一資料結構,每個使用者每天的登入記錄只佔據一位,365天就是365位,僅需要46字節就可存儲,極大節約了儲存空間。

位圖資料結構其實不是一個全新的玩意,我們可以簡單的認為就是個數組,只是裡面的內容只能為0或1而已(二進制位數組)。

2.指令實戰

Redis提供了SETBITGETBITBITCOUNTBITOP四個常用指令用於處理二進位位元組。

  • SETBIT:為位元組指定偏移量上的二進位位元設定值,偏移量從0開始計數,二進位位元的值只能為0或1。傳回原位置值。
  • GETBIT:取得指定偏移量上二進位位元的值。
  • BITCOUNT:統計位元組中值為1的二進位位元數。
  • BITOP:對多個位元組進行位元與、或、異或運算。
127.0.0.1:6379> SETBIT first 0 1    # 0000 0001
(integer) 0
127.0.0.1:6379> SETBIT first 3 1    # 0000 1001
(integer) 0
127.0.0.1:6379> SETBIT first 0 0    # 0000 1000
(integer) 1

127.0.0.1:6379> GETBIT first 0
(integer) 0
127.0.0.1:6379> GETBIT first 3
(integer) 1

127.0.0.1:6379> BITCOUNT first      # 0000 1000
(integer) 1
127.0.0.1:6379> SETBIT first 0 1    # 0000 1001
(integer) 0
127.0.0.1:6379> BITCOUNT first      # 0000 1001
(integer) 2
127.0.0.1:6379> SETBIT first 1 1    # 0000 1011
(integer) 0
127.0.0.1:6379> BITCOUNT first      # 0000 1011
(integer) 3

127.0.0.1:6379> SETBIT x 3 1        
(integer) 0
127.0.0.1:6379> SETBIT x 1 1        
(integer) 0
127.0.0.1:6379> SETBIT x 0 1        # 0000 1011
(integer) 0
127.0.0.1:6379> SETBIT y 2 1        
(integer) 0
127.0.0.1:6379> SETBIT y 1 1        # 0000 0110
(integer) 0
127.0.0.1:6379> SETBIT z 2 1        
(integer) 0
127.0.0.1:6379> SETBIT z 0 1        # 0000 0101
(integer) 0

127.0.0.1:6379> BITOP AND andRes x y z    #0000 0000
(integer) 1
127.0.0.1:6379> BITOP OR orRes x y z      #0000 1111
(integer) 1
127.0.0.1:6379> BITOP XOR x y z           #0000 1000
(integer) 1

# 对给定的位数组进行按位取反
127.0.0.1:6379> SETBIT value 0 1
(integer) 0
127.0.0.1:6379> SETBIT value 3 1            #0000 1001
(integer) 0
127.0.0.1:6379> BITOP NOT notValue value    #1111 0110
(integer) 1

3.BitMap原始碼分析

3.1 資料結構

#如下展示了一個用SDS 表示的一位元組(8位元)長的點陣圖:

的擴充功能:Redis 中的每個物件都是由redisObject 結構表示。

typedef struct redisObject {
// 类型
unsigned type:4;
// 编码
unsigned encoding:4;
unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
// 引用计数
int refcount;
// 执行底层实现的数据结构的指针
void *ptr;
} robj;
  • type 的值為REDIS_STRING表示這是字串物件
  • ##sdshdr .len 的值為1表示這個SDS保存了一個1位元組大小的位數組
  • buf數組中的
  • buf[0]實際上保存了位數組
  • buf數組中的
  • buf[1]為自動追加的\0字元

為了便於我們觀察,buf數組的每個位元組都用一行來表示,buf[i]表示這是buf數組的第i個位元組,buf[i]之後的8個格子表示這個位元組上的8位元。

為再次拉齊各位思想,如下展示了另外一個位數組:

位元組由buf[ 0]、buf[1]和buf[2]三個位元組保存,真實資料為1111 0000 1100 0011 1010 0101

3.2 GETBIT

GETBIT用於傳回位元組在偏移量上的二進位位元的值。 值得我們注意的是,GETBIT的時間複雜度是O(1)

GETBIT指令的執行程序如下:

  1. 計算$ byte = \lfloor offset\p8 \rfloor $ (即>>3),byte 值表示指定的 #                                 o                         f                         f                         s                         e                         t                            offset             offse t 位於位元組的哪個位元組(計算在第幾個行);
  2. 指定                                 b                         u                         f                         [                         i                         ]                            buf[i]             buf[i] 中的                                 i                            i             i#了,接下來就要計算在8個位元組中的第幾位呢?使用 $ bit = (offset\ %\ 8)+1 $计算可得;
  3. 根据                                 b                         y                         t                         e                            byte                 byte                                 b                         i                         t                            bit                 bit 在位数组中定位到目标值返回即可。

GETBIT命令源码如下所示:

void getbitCommand(client *c) {
    robj *o;
    char llbuf[32];
    uint64_t bitoffset;
    size_t byte, bit;
    size_t bitval = 0;
    // 获取offset
    if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset,0,0) != C_OK)
        return;
    // 查找对应的位图对象
    if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
        checkType(c,o,OBJ_STRING)) return;
		// 计算offset位于位数组的哪一行
    byte = bitoffset >> 3;
    // 计算offset在一行中的第几位,等同于取模
    bit = 7 - (bitoffset & 0x7);
    // #define sdsEncodedObject(objptr) (objptr->encoding == OBJ_ENCODING_RAW || objptr->encoding == OBJ_ENCODING_EMBSTR)
    if (sdsEncodedObject(o)) {
        // SDS 是RAW 或者 EMBSTR类型
        if (byte ptr))
            // 获取指定位置的值
            // 注意它不是真正的一个二维数组不能用((uint8_t*)o->ptr)[byte][bit]去获取呀~
            bitval = ((uint8_t*)o->ptr)[byte] & (1 ptr))
            bitval = llbuf[byte] & (1 <p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/dcf5e7b1477d173fa5e3bd707f8d8c79-3.png?x-oss-process=image/resize,p_40" class="lazy" alt=""></p><h4 id="举个栗子">举个栗子</h4><p>以<code>GETBIT array 3</code>为例,<code>array</code>表示上图中三个字节的位数组。</p><pre class="brush:php;toolbar:false">1. $byte = \lfloor 3 \p8 \rfloor$ 得到值为0,说明在 $buf[0]$ 上
2. $bit = (3\ mod\ 8 ) + 1$得到值为4
3. 定位到 $buf[0]$ 字节的从左至右第4个位置上

因为 GETBIT 命令执行的所有操作都可以在常数时间内完成,所以该命令的算法复杂度为O(1)。

3.3 SETBIT

SETBIT用于将位数组在偏移量的二进制位的值设为value,并向客户端返回旧值。

SITBIT命令的执行过程如下:

  1. 計算 我 e n = ⌊ 哦 F F s e t ÷ 8 ⌋ 1 len = \l地板偏移量÷8\r地板 1 len= #⌊offs et÷#8 ##1##1 #,# 我 e n 倫 le###n################值記錄了保存######### 哦 F F s e t 抵銷 ###offset偏移指定的二進位位元至少需要多少位元組
  2. #檢查位元組的長度是否小於                                 l                         e                         n                            len             len#,如果是的話,將SDS的長度擴展為len字節,並將所有新擴展空間的二進位位設置為0
  3. #計算# 乙 y t e = ⌊ 哦 F F s e t ÷ 8 ⌋ 位元組 = \lfloor 偏移÷8\rfloor 位元組 =offset÷8 乙 y t e 位元組 位元組 值表示指定的 哦 F F s e t 抵銷 #############fset#位於位元組的那個位元組(就是計算在那個#                                 b                         u                         f                         [                         i                         ]                            buf[i]             buf[i]中的                                 i                            i                 i#)
  4. ##使用
  5. 乙 我 t = ( 哦 F F s e t 米 哦 d 8 ) 1 位元 = (偏移\ mod\ 8) 1 bi#t##= (o#ff##set mo##d 8)##1 計算可得目標## 乙 你 F [ 我 ] 緩衝區[i] buf[i]的具體第幾位
  6. 根据                                 b                         y                         t                         e                            byte                 byte                                 b                         i                         t                            bit                 bit的值,首先保存                                 o                         l                         d                         V                         a                         l                         u                         e                            oldValue                 oldValue,然后将新值                                 v                         a                         l                         u                         e                            value                 value设置到目标位上
  7. 返回旧值

因为SETBIT命令执行的所有操作都可以在常数时间内完成,所以该命令的算法复杂度为O(1)。

SETBIT命令源码如下所示:

void setbitCommand(client *c) {
    robj *o;
    char *err = "bit is not an integer or out of range";
    uint64_t bitoffset;
    ssize_t byte, bit;
    int byteval, bitval;
    long on;
    // 获取offset
    if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset,0,0) != C_OK)
        return;
    // 获取我们需要设置的值
    if (getLongFromObjectOrReply(c,c->argv[3],&on,err) != C_OK)
        return;

    /* 判断指定值是否为0或1 */
    if (on & ~1) {
        // 设置了0和1之外的值,直接报错
        addReplyError(c,err);
        return;
    }
    // 根据key查询SDS对象(会自动扩容)
    if ((o = lookupStringForBitCommand(c,bitoffset)) == NULL) return;

    /* 获得当前值 */
    byte = bitoffset >> 3;
    byteval = ((uint8_t*)o->ptr)[byte];
    bit = 7 - (bitoffset & 0x7);
    bitval = byteval & (1 ptr)[byte] = byteval;
    // 发送数据修改通知
    signalModifiedKey(c,c->db,c->argv[1]);
    notifyKeyspaceEvent(NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
    server.dirty++;
    addReply(c, bitval ? shared.cone : shared.czero);
}

舉個栗子1.0

array表示上圖中的三個位元組位數組。以SETBIT array 10 1為例:

  1. $ len = \lfloor10÷8\rfloor 1$得到值為2,說明至少需要2位元組長的位數組
  2. 檢查是否需要擴容,不需要
  3. 計算$byte = 1                                 ,                         計                         算                            ,計算             bit = 3                                 ,                         保                         存                            ,保存             投保oldValue$ ,設定新值
  4. 返回                                 o                         l                         d                         V                         a                         l                         u                         e                            oldValue             ol#dV##alue

舉個栗子2.0

假設目標位數組為1位元組長度。執行

SETBIT array 12 1,執行如下:

  1. #                                 l                         e                         n                         =                         ⌊                         12                         ÷                         8                         ⌋                                                 1                            len = ⌊12÷8⌋ 1             len=12÷ 8 #1 得到值為2,說明需要2位元組長的SDS
  2. #檢查是否需要擴容,需要呀!由 SDS 的自動擴容機制可知, SDS 將以新長度的兩倍擴容。
  3. 計算 $byte = 1 $
  4. 計算 $bit = 5 $
  5. #儲存                                 o                         l                         d                         V                         a                         l                         u                         e                            oldValue             ol#dV##alue#,設定新值
  6. 返回
  7. #                                 o                         l                         d                         V                         a                         l                         u                         e                            oldValue             ol#dV##alue

3.4 BITCOUNT

BITCOUNT

指令用於統計給定位數組中值為1的二進位位元的數量。功能似乎不複雜,但實際上要有效率地實作這個指令並不容易,需要用到一些精巧的演算法。

統計一個位元組中非0二進位位元的數量在數學上被稱為"計算漢明重量"。

3.4.1 暴力遍歷

實作

BITCOUNT

指令最簡單直接的方法,就是遍歷位數群組中的每個二進位位,並在遇到值為1的二進位位元時將計數器加1。

小數據量還好,大數據量直接PASS!

#3.4.2 查表法

對於一個有限集合來說,集合元素的排列方式是有限的,對於一個有限長度的位數組來說,它能表示的二進位位排列也是有限的。根據這個原理,我們可以建立一個表,表的鍵為某種排列的位數組,而表的值則是對應位數組中值為1的二進位位元的數量。

對於8位長的位數組來說,我們可以建立下表,透過這個表格我們可以一次從位數組中讀入8位,然後根據這8位的值進行查表,直接知道這個值包含了多少個1。

可惜,查表法耗記憶體呀!

3.4.3 二进制位统计算法:variable-precision SWAR

目前已知效率最好的通用算法为variable-precision SWAR算法,该算法通过一系列位移和位运算操作,可以在常数时间(这就很牛逼了)内计算多个字节的汉明重量,并且不需要使用任何额外的内存。

SWAR算法代码如下所示:

uint32_t swar(uint32_t i) {
    // 5的二进制:0101
    i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
    // 3的二进制:0011
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
    i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
    i = (i*(0x01010101) >> 24);
    return i;
  
    i = i - ((i >> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
    return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}

下面描述一下这几步都干了啥:

  1. 步骤一计算出的值i的二进制表示可以按每两个二进制位为一组进行分组,各组的十进制表示就是该组的1的数量;
  2. 步骤二计算出的值i的二进制表示可以按每四个二进制位为一组进行分组,各组的十进制表示就是该组的1的数量;
  3. 步骤三计算出的值i的二进制表示可以按每八个二进制位为一组进行分组,各组的十进制表示就是该组的1的数量;
  4. 步骤四的i*0x01010101语句计算出bitarray中1的数量并记录在二进制位的最高八位,而>>24语句则通过右移运算,将bitarray的汉明重量移动到最低八位,得出的结果就是bitarray的汉明重量。
举个栗子

对于调用swar(0xFBB4080B),步骤一将计算出值0xA6640406,这个值表的每两个二进制位的十进制表示记录了0xFBB4080B每两个二进制位的汉明重量。

步骤二将计算出值0x43310103,这个值表的每四个二进制位的十进制表示记录了0xFBB4080B每四个二进制位的汉明重量。

步骤三将计算出值0x7040103,这个值表的每八个二进制位的十进制表示记录了0xFBB4080B每八个二进制位的汉明重量。

步骤四首先计算0x7040103 * 0x01010101 = 0xF080403,将汉明重量聚集到二进制位的最高八位。

之后计算0xF080403 >> 24,将汉明重量移动到低八位,得到最终值0x1111,即十进制15。

如果您是Java程序员,可以去看看Integer.bitCount方法,也是基于SWAR算法的思想哦!

大家也可以看看StackFlow上大神对它的讲解:[How does this algorithm to count the number of set bits in a 32-bit integer work?](https://stackoverflow.com/questions/22081738/how-does-this-algorithm-to-count-the-number-of-set-bits-in-a-32-bit-integer-work)3.4.4 源码分析

Redis 中通过调用redisPopcount方法统计汉明重量,源码如下所示:

long long redisPopcount(void *s, long count) {
    long long bits = 0;
    unsigned char *p = s;
    uint32_t *p4;
    // 为查表法准备的表
    static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
    // CPU一次性读取8个字节,如果4字节跨了两个8字节,需要读取两次才行
    // 所以考虑4字节对齐,只需读取一次就可以读取完毕
    while((unsigned long)p & 3 && count) {
        bits += bitsinbyte[*p++];
        count--;
    }

    // 一次性处理28字节,单独看一个aux就容易理解了,其实就是SWAR算法
    // uint32_t:4字节
    p4 = (uint32_t*)p;
    while(count>=28) {
        uint32_t aux1, aux2, aux3, aux4, aux5, aux6, aux7;

        aux1 = *p4++;// 一次性读取4字节
        aux2 = *p4++;
        aux3 = *p4++;
        aux4 = *p4++;
        aux5 = *p4++;
        aux6 = *p4++;
        aux7 = *p4++;
        count -= 28;// 共处理了4*7=28个字节,所以count需要减去28

        aux1 = aux1 - ((aux1 >> 1) & 0x55555555);
        aux1 = (aux1 & 0x33333333) + ((aux1 >> 2) & 0x33333333);
        aux2 = aux2 - ((aux2 >> 1) & 0x55555555);
        aux2 = (aux2 & 0x33333333) + ((aux2 >> 2) & 0x33333333);
        aux3 = aux3 - ((aux3 >> 1) & 0x55555555);
        aux3 = (aux3 & 0x33333333) + ((aux3 >> 2) & 0x33333333);
        aux4 = aux4 - ((aux4 >> 1) & 0x55555555);
        aux4 = (aux4 & 0x33333333) + ((aux4 >> 2) & 0x33333333);
        aux5 = aux5 - ((aux5 >> 1) & 0x55555555);
        aux5 = (aux5 & 0x33333333) + ((aux5 >> 2) & 0x33333333);
        aux6 = aux6 - ((aux6 >> 1) & 0x55555555);
        aux6 = (aux6 & 0x33333333) + ((aux6 >> 2) & 0x33333333);
        aux7 = aux7 - ((aux7 >> 1) & 0x55555555);
        aux7 = (aux7 & 0x33333333) + ((aux7 >> 2) & 0x33333333);
        bits += ((((aux1 + (aux1 >> 4)) & 0x0F0F0F0F) +
                    ((aux2 + (aux2 >> 4)) & 0x0F0F0F0F) +
                    ((aux3 + (aux3 >> 4)) & 0x0F0F0F0F) +
                    ((aux4 + (aux4 >> 4)) & 0x0F0F0F0F) +
                    ((aux5 + (aux5 >> 4)) & 0x0F0F0F0F) +
                    ((aux6 + (aux6 >> 4)) & 0x0F0F0F0F) +
                    ((aux7 + (aux7 >> 4)) & 0x0F0F0F0F))* 0x01010101) >> 24;
    }
    /* 剩余的不足28字节,使用查表法统计 */
    p = (unsigned char*)p4;
    while(count--) bits += bitsinbyte[*p++];
    return bits;
}

不难发现 Redis 中同时运用了查表法SWAR算法完成BITCOUNT功能。

4.面试题:40亿QQ号去重

如果没有1GB的内存限制,我们可以使用排序和Set完成这个算法:

  • 排序:① 首先将40亿个QQ号进行排序;② 从小到大遍历,跳过重复元素只取第一个元素。
  • Set:将40亿个QQ号统统放进Set集合中,自动完成去重,Perfect

这样回答是要GG的节奏呀!

对40亿个QQ号进行排序需要多少时间?这个存储了40亿QQ号的数组容量已经超过1GB了,同理Set集合存储这么多的QQ号也导致内存超限了。

BitMap去重

**这不巧了么~我们可以使用刚刚学的BITMAP来去重呀!**一个字节可以记录8个数是否存在(类似于计数排序),将QQ号对应的offset的值设置为1表示此数存在,遍历完40亿个QQ号后直接统计BITMAP上值为1的offset即可完成QQ号的去重。

如果是对40亿个QQ号进行排序也是可以用位图完成的哦~一样的思想

5.位图实战

既然我们深入了解了BITMAP,那不进行个实战项目可说不过去呀!

我们使用BITMAP实现GITHUB中统计每天提交次数的这个小功能,基于SpringBoot+Echarts实现

如果是记录登录状态我们可以很方便的使用0和1记录,如果是记录提交次数就显得BITMAP无用了,没关系,我们可以使用一个字节来记录提交次数,只是在业务上需要处理好十进制和二进制直接的转换而已。

生成模拟数据

public void genTestData() {
    if(redisUtils.isExist(CommonConstant.KEY)){
        return;
    }
    // 获取当前年的总天数
    int days = getDays();
    for (int i = 0; i <h4 id="获取数据">获取数据</h4><pre class="brush:php;toolbar:false">public List<string> getPushData() {
    List<string> res = new ArrayList(366);
    // 没有数据就先造数据
    genTestData();
    int days = getDays();
    for(long i=0;i<days><blockquote><p><strong>这里觉得可以直接将所有的bit统统返回,在前端进行分割处理</strong></p></blockquote>
<h4 id="前端渲染">前端渲染</h4>
<pre class="brush:php;toolbar:false"><script>
    var chartDom = document.getElementById(&#39;main&#39;);
    var myChart = echarts.init(chartDom);
    var option;

    function getVirtulData(year) {
        var date = +echarts.number.parseDate(year + &#39;-01-01&#39;);
        var end = +echarts.number.parseDate(+year + 1 + &#39;-01-01&#39;);
        var dayTime = 3600 * 24 * 1000;
        var data = [];
        $.ajax({
            "url":&#39;http://localhost:8080/test/getPushData&#39;,
            "async":false, // ajax同步获取
            success:function (res){
                for (let time = date,k=0; time < end && k < res.data.length; time += dayTime,k++) {
                    data.push([
                        echarts.format.formatTime(&#39;yyyy-MM-dd&#39;, time),
                        parseInt(res.data[k],2)//客户端完成进制转换,不放在服务端完成
                    ]);
                }
            }
        })

        return data;
    }
    option = {
        title: {
            top: 30,
            left: &#39;left&#39;,
            text: &#39;BitMap Demo&#39;
        },
        tooltip: {},
        visualMap: {
            min: 0,
            max: 32,
            type: &#39;piecewise&#39;,
            orient: &#39;horizontal&#39;,
            left: &#39;right&#39;,
            top: 220,
            pieces: [
                {min: 0, max: 0,label:"less"},
                {min: 1, max: 10,label:" "},
                {min: 1, max: 20,label:" "},
                {min: 21, max: 40,label:" "},
                {min: 41, max: 64,label:"more"},
            ],
            inRange: {
                color: [ &#39;#EAEDF0&#39;, &#39;#9AE9A8&#39;, &#39;#41C363&#39;, &#39;#31A14E&#39;, &#39;#206D38&#39; ],//颜色设置 
                colorAlpha: 0.9,//透明度
            }
        },
        calendar: {
            top: 120,
            left: 30,
            right: 30,
            cellSize: 13,
            range: &#39;2022&#39;,
            splitLine: { show: false },//不展示边线
            itemStyle: {
                borderWidth: 0.5
            },
            yearLabel: { show: false }
        },
        series: {
            type: &#39;heatmap&#39;,
            coordinateSystem: &#39;calendar&#39;,
            data: getVirtulData(&#39;2022&#39;)
        }
    };

    option && myChart.setOption(option);</script>

推荐学习:Redis视频教程

以上是一文搞懂redis的bitmap的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:CSDN。如有侵權,請聯絡admin@php.cn刪除
Redis是SQL還是NOSQL數據庫?答案解釋了Redis是SQL還是NOSQL數據庫?答案解釋了Apr 18, 2025 am 12:11 AM

RedisisclassifiedasaNoSQLdatabasebecauseitusesakey-valuedatamodelinsteadofthetraditionalrelationaldatabasemodel.Itoffersspeedandflexibility,makingitidealforreal-timeapplicationsandcaching,butitmaynotbesuitableforscenariosrequiringstrictdataintegrityo

REDIS:提高應用程序性能和可擴展性REDIS:提高應用程序性能和可擴展性Apr 17, 2025 am 12:16 AM

Redis通過緩存數據、實現分佈式鎖和數據持久化來提升應用性能和可擴展性。 1)緩存數據:使用Redis緩存頻繁訪問的數據,提高數據訪問速度。 2)分佈式鎖:利用Redis實現分佈式鎖,確保在分佈式環境中操作的安全性。 3)數據持久化:通過RDB和AOF機制保證數據安全性,防止數據丟失。

REDIS:探索其數據模型和結構REDIS:探索其數據模型和結構Apr 16, 2025 am 12:09 AM

Redis的數據模型和結構包括五種主要類型:1.字符串(String):用於存儲文本或二進制數據,支持原子操作。 2.列表(List):有序元素集合,適合隊列和堆棧。 3.集合(Set):無序唯一元素集合,支持集合運算。 4.有序集合(SortedSet):帶分數的唯一元素集合,適用於排行榜。 5.哈希表(Hash):鍵值對集合,適合存儲對象。

REDIS:對其數據庫方法進行分類REDIS:對其數據庫方法進行分類Apr 15, 2025 am 12:06 AM

Redis的數據庫方法包括內存數據庫和鍵值存儲。 1)Redis將數據存儲在內存中,讀寫速度快。 2)它使用鍵值對存儲數據,支持複雜數據結構,如列表、集合、哈希表和有序集合,適用於緩存和NoSQL數據庫。

為什麼要使用redis?利益和優勢為什麼要使用redis?利益和優勢Apr 14, 2025 am 12:07 AM

Redis是一個強大的數據庫解決方案,因為它提供了極速性能、豐富的數據結構、高可用性和擴展性、持久化能力以及廣泛的生態系統支持。 1)極速性能:Redis的數據存儲在內存中,讀寫速度極快,適合高並發和低延遲應用。 2)豐富的數據結構:支持多種數據類型,如列表、集合等,適用於多種場景。 3)高可用性和擴展性:支持主從復制和集群模式,實現高可用性和水平擴展。 4)持久化和數據安全:通過RDB和AOF兩種方式實現數據持久化,確保數據的完整性和可靠性。 5)廣泛的生態系統和社區支持:擁有龐大的生態系統和活躍社區,

了解NOSQL:Redis的關鍵特徵了解NOSQL:Redis的關鍵特徵Apr 13, 2025 am 12:17 AM

Redis的關鍵特性包括速度、靈活性和豐富的數據結構支持。 1)速度:Redis作為內存數據庫,讀寫操作幾乎瞬時,適用於緩存和會話管理。 2)靈活性:支持多種數據結構,如字符串、列表、集合等,適用於復雜數據處理。 3)數據結構支持:提供字符串、列表、集合、哈希表等,適合不同業務需求。

REDIS:確定其主要功能REDIS:確定其主要功能Apr 12, 2025 am 12:01 AM

Redis的核心功能是高性能的內存數據存儲和處理系統。 1)高速數據訪問:Redis將數據存儲在內存中,提供微秒級別的讀寫速度。 2)豐富的數據結構:支持字符串、列表、集合等,適應多種應用場景。 3)持久化:通過RDB和AOF方式將數據持久化到磁盤。 4)發布訂閱:可用於消息隊列或實時通信系統。

REDIS:流行數據結構指南REDIS:流行數據結構指南Apr 11, 2025 am 12:04 AM

Redis支持多種數據結構,具體包括:1.字符串(String),適合存儲單一值數據;2.列表(List),適用於隊列和棧;3.集合(Set),用於存儲不重複數據;4.有序集合(SortedSet),適用於排行榜和優先級隊列;5.哈希表(Hash),適合存儲對像或結構化數據。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版