[Redis] Redis データ型の詳細な調査 - ハッシュ テーブル ハッシュ


序文

アプリケーションを構築および最適化する場合、データ キャッシュはパフォーマンスを向上させ、データベースの負荷を軽減するための重要な戦略の 1 つです。Redis (Remote Dictionary Server) は、データ キャッシュと高速データ アクセスに広く使用されている高性能インメモリ データベースです。その中でも、ハッシュ タイプ (Hash) は Redis の強力なデータ構造であり、通常、オブジェクト、マッピング関係、およびキーと値のデータを保存するために使用されます。

この記事では、Redis のハッシュ タイプについて詳しく説明します。ハッシュ タイプの基本的なコマンドから始めて、その使用方法、内部エンコーディング、実際のアプリケーション シナリオでの応用方法を徐々に紹介します。Redis ハッシュ タイプを学習して理解することで、Redis をより有効に活用してデータ ストレージとアクセスを最適化し、アプリケーションのパフォーマンスを向上させることができます。

次に、Redis のハッシュ タイプを詳しく見てみましょう。

1. ハッシュタイプに関するコマンド

1.1 HSET と HSETNX

  1. HSET
  • 機能: 指定されたハッシュ テーブルのフィールドの値を設定し、フィールドが存在する場合は更新し、存在しない場合は作成します。また、複数のフィールドのセットを同時に設定できます。

  • 文法:

    HSET key field value [field value ... ]
    
  1. HSETNX
  • 機能: フィールドが存在しない場合にのみ、指定されたハッシュ テーブル内のフィールドの値を設定します。設定が成功した場合は 1 を返し、そうでない場合は 0 を返します。
  • 文法:
    HSETNX key field value 
    
  1. 使用例

1.2 HGET と HMGET

  1. HGET
  • 機能: 指定されたハッシュテーブルのフィールドの値を取得します。
  • 文法:
    HGET key field
    
  1. HMGET
  • 機能: 指定されたハッシュテーブル内の複数のフィールドの値を取得します。
  • 文法:
    HMGET key field1 [field2 ...]
    
  1. 使用例

もちろん、ハッシュ タイプ関連のコマンドの詳細な手順をカバーするために、以下のセクションを改善し続けます。

1.3 HKEYS、ホエール、ヘゲタル

  1. HKEYS
  • 機能: 指定されたハッシュ テーブル内のすべてのフィールドの名前を取得します。
  • 文法:
    HKEYS key
    
  1. HVALS
  • 機能: 指定されたハッシュテーブル内のすべてのフィールドの値を取得します。
  • 文法:
    HVALS key
    
  1. HGETALL
  • 機能: 指定されたハッシュ テーブル内のすべてのフィールドと対応する値を取得します。
  • 文法:
    HGETALL key
    
  1. 使用例

1.4 HEXISTS と HDEL

  1. HEXISTS
  • 機能: 指定されたハッシュテーブルにフィールドが存在するかどうかを確認します。
  • 文法:
    HEXISTS key field
    
  1. HDEL
  • 機能: 指定されたハッシュ テーブル内の 1 つ以上のフィールドを削除します。
  • 文法:
    HDEL key field1 [field2 ...]
    
  1. 使用例

1.5 履行

  1. HLEN
  • 機能: 指定されたハッシュ テーブル内のフィールドの数 (つまり、ハッシュ テーブルのサイズ) を取得します。
  • 文法:
    HLEN key
    
  1. 使用例

1.6 HINCRBY と HINCRBYFLOAT

  1. HINCRBY
  • 機能: ハッシュ テーブルの指定されたフィールドの値を整数ずつ増やします。
  • 文法:
    HINCRBY key field increment
    
  1. HINCRBYFLOAT
  • 機能: ハッシュ テーブルの指定されたフィールドの値を浮動小数点数で増加します。
  • 文法:
    HINCRBYFLOAT key field increment
    
  1. 使用例

1.7 ハッシュ関連コマンドの概要

以下は、コマンド、関数、時間計算量など、ハッシュ タイプに関連するコマンドの概要です。

注文 効果 時間の複雑さ
HSET ハッシュ テーブル内のフィールドの値を設定し、存在する場合は更新し、存在しない場合は作成します。複数のフィールドのセットを同時に設定できます。 ○(1)
HSETNX フィールドが存在しない場合にのみハッシュ テーブルにフィールドの値を設定し、成功した場合は 1 を返し、それ以外の場合は 0 を返します。 ○(1)
HGET 指定されたハッシュ テーブル内のフィールドの値を取得します。 ○(1)
HMGET 指定されたハッシュ テーブル内の複数のフィールドの値を取得します。 O(N)、N はフィールドの数です
HKEYS 指定されたハッシュ テーブル内のすべてのフィールドの名前を取得します。 O(N)、N はフィールドの数です
くじら 指定されたハッシュ テーブル内のすべてのフィールドの値を取得します。 O(N)、N はフィールドの数です
ヘゲタール 指定されたハッシュ テーブル内のすべてのフィールドと対応する値を取得します。 O(N)、N はフィールドの数です
異端者 指定されたハッシュ テーブルにフィールドが存在するかどうかを確認します。 ○(1)
HDEL 指定されたハッシュ テーブル内の 1 つ以上のフィールドを削除します。 O(N)、N は削除されたフィールドの数です
ヘレン 指定されたハッシュ テーブル内のフィールドの数 (つまり、ハッシュ テーブルのサイズ) を取得します。 ○(1)
ヒンクラビー ハッシュ テーブル内の指定されたフィールドの値を整数ずつ増やします。 ○(1)
HINCRBYFLOAT ハッシュ テーブル内の指定されたフィールドの値を浮動小数点数だけ増加します。 ○(1)

2. ハッシュタイプの内部エンコーディング

Redis は、ハッシュを含む複数のデータ構造をサポートする高性能インメモリ データベースです。Redis では、ハッシュ データ型には 2 つの内部エンコード方式、つまり ziplist (圧縮リスト) と hashtable (ハッシュ テーブル) があります。これら 2 つのエンコード方法のどちらを選択するかは、ハッシュのサイズとストレージの特性によって異なります。

1. ziplist (圧縮リスト):

ziplist は、より小さいハッシュを内部でエンコードするための Redis のコンパクトなデータ構造です。ziplist の主な機能をいくつか紹介します。

  • ハッシュ タイプの要素の数が比較的少なく、すべてのフィールドと対応する値が特定の制限を満たす場合、Redis はハッシュの内部実装として ziplist を使用します。
  • デフォルトでは、Redis は ziplist を選択します。具体的には、ハッシュの要素が 512 個以下で、すべての値が 64 バイト未満の場合、ziplist が推奨されるエンコードです。
  • Ziplist はコンパクトなデータ構造であり、メモリの節約においてハッシュテーブルよりも優れたパフォーマンスを発揮します。複数のハッシュ要素を連続してまとめて保存し、メモリ使用量を効果的に削減します。

2. ハッシュテーブル:

Hashtable は、大規模なハッシュ データを保存するために Redis で使用される内部エンコーディングです。ハッシュテーブルの主な機能は次のとおりです。

  • ハッシュ タイプの要素の数が ziplist 構成の制限を超える場合、またはフィールドの対応する値が 64 バイトを超える場合、Redis は内部エンコーディングをハッシュテーブルに切り替えます。
  • Hashtable はハッシュ テーブル データ構造で、読み取りおよび書き込み時間の複雑さが O(1) であり、大規模なハッシュ データ セットに適しています。
  • ハッシュテーブルに切り替えると、特に大きなハッシュを扱う場合や大きな値が含まれる場合に、パフォーマンスとメモリ管理が向上します。

上記の説明に基づいて、ハッシュ データ型の内部エンコードと、エンコード変換が行われる条件を示す例をいくつか示します。

例 1: ziplist エンコーディングの使用

> hmset hashkey f1 v1 f2 v2
OK
> object encoding hashkey
"ziplist"

この例では、フィールドの数が少なく、値が満足できるため、Redis は内部エンコードとして ziplist を使用します。

例 2: ハッシュテーブル エンコーディングに切り替える

> hset hashkey f3 "one string is bigger than 64 bytes ..." 1
OK
> object encoding hashkey
"hashtable"

この例では、フィールドの 1 つが 64 バイトより大きい値に対応しているため、Redis は内部エンコーディングをハッシュテーブルに切り替えます。

例 3: ハッシュテーブル エンコーディングに切り替える

> hmset hashkey f1 v1 h2 v2 f3 v3 ... (超过 512 个字段) ...
OK
> object encoding hashkey
"hashtable"

この例では、フィールド数が 512 を超えているため、Redis は内部エンコーディングをハッシュテーブルに変換します。

これらの内部エンコーディングは、さまざまな状況でメモリ使用量とパフォーマンスのバランスをとるために選択されます。Redis は、ストレージと操作の効率を最適化するために、必要に応じてこれらのエンコード変換を自動的に実行します。ハッシュされたデータセットのサイズに関係なく、Redis は構成とデータの特性に基づいて適切な内部エンコーディングをインテリジェントに選択します。この自動最適化により、さまざまなワークロード下で Redis の優れたパフォーマンスが保証されます。

3. ハッシュ型の適用シナリオ

このセクションでは、アプリケーションにおけるハッシュ タイプの実際的な使用方法を検討します。まず、リレーショナル データベースに格納されるユーザー情報の構造を確認してみましょう。

リレーショナル データ テーブルにはユーザー情報が保存されます

上の図は、リレーショナル データ テーブルに記録された 2 つのユーザー情報を示しています。ユーザー属性はテーブル内の列として表され、各ユーザー情報は行として表されます。Redis でこれら 2 つのユーザー情報をマッピングする場合は、ハッシュ タイプを使用できます。

ハッシュ タイプを使用してユーザー情報をマップします。

マッピング関係はユーザー情報を表します

JSON 形式の文字列を使用してユーザー情報をキャッシュする場合と比較して、ハッシュ タイプは更新操作においてより直観的で柔軟です。次の疑似コードのように、各ユーザーの ID をキーのサフィックスとして定義し、複数のフィールド値を使用してユーザーの各属性に対応させることができます。

UserInfo getUserInfo(long uid) {
    
    
    // 根据 uid 得到 Redis 的键
    String key = "user:" + uid;

    // 尝试从 Redis 中获取对应的值
    userInfoMap = Redis 执行命令:hgetall key;

    // 如果缓存命中(hit)
    if (userInfoMap != null) {
    
    
        // 将映射关系还原为对象形式
        UserInfo userInfo = 利用映射关系构建对象(userInfoMap);
        return userInfo;
    }

    // 如果缓存未命中(miss)
    // 从数据库中,根据 uid 获取用户信息
    UserInfo userInfo = MySQL 执行 SQL:select * from user_info where uid = <uid>;

    // 如果表中没有 uid 对应的用户信息
    if (userInfo == null) {
    
    
        响应 404;
        return null;
    }

    // 将缓存以哈希类型保存
    Redis 执行命令:hmset key name userInfo.name age userInfo.age city userInfo.city;

    // 写入缓存,为了防止数据腐烂(rot),设置过期时间为 1 小时(3600 秒)
    Redis 执行命令:expire key 3600;

    // 返回用户信息
    return userInfo;
}

上記のコードは、一般的なキャッシュ戦略を示しています。最初に Redis キャッシュからデータを取得しようとし、データが見つからなかった場合はデータベースから取得し、その後のアクセスのために結果を Redis に保存します。この戦略により、アクセス パフォーマンスが向上し、データベースの負担が軽減されます。

ただし、ハッシュ タイプとリレーショナル データベースの間には 2 つの主な違いがあることに注意することが重要です。

  • ハッシュ タイプの疎性:ハッシュ タイプでは各キーに異なるフィールドを持つことができますが、リレーショナル データベースでは新しい列を追加するときにすべての行に値 (null であっても) を設定する必要があります。

  • 複雑なリレーショナル クエリの非適用性:リレーショナル データベースは複雑なリレーショナル クエリをサポートしますが、Redis は結合テーブル クエリや集計クエリなどの複雑なリレーショナル クエリのシミュレーションには適しておらず、メンテナンス コストが高くなります。

リレーショナル データベースにおけるスパース性の例:

リレーショナルデータベースのスパース性

ハッシュ タイプを使用すると、ユーザー情報をより直感的にマッピングして保存し、さまざまなアプリケーション シナリオのニーズに適応できます。ハッシュ タイプはシンプル、直観的かつ柔軟に使用できるため、ローカル属性の変更やクエリ操作に特に適しており、メモリ効率も優れています。

4. ネイティブ、シリアル化、ハッシュ型キャッシュ方式の比較

ユーザー情報のキャッシュに関しては、さまざまなキャッシュ方法から選択できます。以下は、ネイティブ文字列タイプ、シリアル化された文字列タイプ (JSON 形式など)、およびハッシュ タイプという 3 つの一般的なキャッシュ方法の詳細な比較と分析です。ここでは、アプリケーションに適したキャッシュ戦略をより適切に選択できるように、その実装方法、利点、欠点を検討します。

4.1 ネイティブ文字列型

実装方法:ネイティブ文字列タイプを使用して、各ユーザー属性を個別のキーと値のペアとして保存します。次に例を示します。

set user:1:name James
set user:1:age 23
set user:1:city Beijing

アドバンテージ:

  • 実装が簡単で、各属性は個別のキーで保存されるため、理解と保守が簡単になります。
  • 個々の属性の変更に非常に柔軟です。

欠点:

  • 占有するキーが多すぎると、メモリ使用量が多くなります。
  • ユーザー情報は Redis に分散して保存されているため、統一性に欠け、バッチ操作や管理には不便です。
  • 一度に完全なユーザー情報を取得する必要があり、多数のキー操作が必要な場合には適していません。

適用可能なシナリオ:この方法は、ユーザー属性を個別に頻繁に変更する必要があるシナリオには適していますが、完全なユーザー情報を一度に取得する必要があるシナリオには適していません。

4.2 シリアル化された文字列型(JSON形式など)

実装方法:シリアル化された文字列タイプを使用して、ユーザー情報を JSON 形式でシリアル化し、キーと値のペアとして保存します。次に例を示します。

set user:1 {
    
    "name": "James", "age": 23, "city": "Beijing"}

アドバンテージ:

  • 装置全体を操作部として情報を記憶するのに適しており、プログラミングも比較的簡単です。
  • メモリを効率的に使用でき、特に大きなオブジェクトやデータ構造の保存に適しています。

欠点:

  • シリアル化と逆シリアル化にはある程度のオーバーヘッドが必要です。
  • 頻繁な更新や個々の属性のクエリには適しておらず、柔軟性に欠けます。

適用可能なシナリオ:この方法は、完全なユーザー情報を一度に取得する必要があるシナリオ、特にユーザー情報が複雑なオブジェクトまたはデータ構造である場合に適しています。

4.3 ハッシュタイプ

実装方法:ハッシュ タイプを使用して、ユーザー情報を Redis ハッシュ タイプとして保存します。次に例を示します。

hmset user:1 name James age 23 city Beijing

アドバンテージ:

  • シンプル、直感的、そして柔軟です。
  • 情報のローカル変更または取得操作に適しており、単一属性の読み取りと書き込みをサポートします。
  • 内部エンコードはジップリストまたはハッシュテーブルにすることができ、柔軟性とメモリ効率が向上します。

欠点:

  • ziplist と hashtable の 2 つの内部エンコーディング間のハッシュの変換を制御する必要があるため、メモリ消費が発生する可能性があります。
  • 完全なユーザー情報を一度に取得する必要があり、複数回読み取る必要がある場合には適していません。

適用可能なシナリオ:ハッシュ タイプは、ユーザー属性に対するローカルな変更または頻繁な個々の属性操作が必要なシナリオに適しており、属性の柔軟なクエリが必要な状況にも適しています。

4.4 概要

適切なキャッシュ方法の選択は、特定のアプリケーションのニーズとアクセス パターンに基づいて決定する必要があります。通常、これら 3 つのキャッシュ方法は、さまざまなデータ特性と運用要件に基づいて包括的に検討され、アプリケーションで適切に組み合わせて使用​​されることで、最高のパフォーマンスと柔軟性が得られます。

たとえば、ハッシュ タイプのキャッシュはローカル属性の変更やクエリを処理するために使用でき、シリアル化された文字列タイプのキャッシュは完全なユーザー情報を取得するために使用できます。これにより、Redis の利点を最大限に活用して、柔軟性と保守性を維持しながらデータ アクセスの効率を向上させることができます。

おすすめ

転載: blog.csdn.net/qq_61635026/article/details/132768903