MySQLはデータベースのN+1クエリ問題を解決します

MySQLはデータベースのN+1クエリ問題を解決します

導入

HibernateやMyBatisなどのORMフレームワークでは、部門に関連付けられたユーザーオブジェクトなどの関連オブジェクトを設定できます。
n人のユーザーが見つかった場合、n個の部門クエリが必要です。ユーザーをクエリすることは選択操作であり、ユーザーの関連をクエリすることは
dept は n 回なので、n+1 の問題ですが、1+n と呼ぶ方が適切です。

mybatisの設定

ユーザーマッパー.xml

<resultMap id="BaseResultMap" タイプ="testmaven.entity.User">
  <id 列="id" jdbcType="INTEGER" プロパティ="id" />
  <結果列="名前" jdbcType="VARCHAR" プロパティ="名前" />
  <結果列="年齢" jdbcType="INTEGER" プロパティ="年齢" />
  <結果列="dept_id" jdbcType="INTEGER" プロパティ="deptId" />
  <関連付けプロパティ="dept" 列="dept_id" fetchType="eager" select="testmaven.mapper.DeptMapper.selectByPrimaryKey" ></関連付け>
 </結果マップ>

データテーブルは次のとおりです。

部門テーブル

|ID|名前|

ユーザーテーブル

|id|名前|部門ID|

要件は、次の構造を持つデータを取得することです。

[
  { "id":1, "name":"テスト", "department_id":1, "department":{ "id":1, "name":"テスト部門"
    }
  }
]

方法1: ループクエリ

ユーザーリストを照会する

対応する部門情報を照会するための循環ユーザーリスト

$users = $db->query('SELECT * FROM `user`'); foreach($users as &$user) {
  $users['department'] = $db->query('SELECT * FROM `department` WHERE `id` = '.$user['department_id']);
}

この方法では、1+N クエリ (リストへのクエリ 1 つ、部門へのクエリ N つ) が実行されますが、パフォーマンスが最も低いため、お勧めできません。

方法2: テーブルを結合する

結合テーブルを通じてユーザーと部門のデータを照会する

返されたデータの処理

$users = $db->query('SELECT * FROM `user` INNER JOIN `department` ON `department`.`id` = `user`.`department_id`'); // 手動処理では、必要な構造として結果が返されます

この方法には実際には制限があります。ユーザーと部門が同じサーバー上にない場合、テーブルを結合することはできません。

方法3: 1+1クエリ

このメソッドはまずユーザーリストを一度照会します

リストから部門IDを取り出して配列を形成する

ステップ2で部門を問い合わせる

最終データを統合する

コードは大まかに次のようになります。

$users = $db->query('SELECT * FROM `user`');
$departmentIds = [ ]; foreach($users を $user として) { if(!in_array($user['department_id'], $departmentIds)) {
    $departmentIds[] = $user['department_id'];
  }
}
$departments = $db->query('SELECT * FROM `department` WHERE id in ('.join(',',$department_id).')');
$map = []; // [部門ID => 部門項目]foreach($departments as $department) {
  $map[$department['id']] = $department;
}foreach($users を $user として) {
  $user['department'] = $map[$user['department_id']] ?? null;
 }

この方法は 2 つのテーブルに制限がなく、マイクロサービスの現在の人気を考慮すると、より優れたアプローチです。

以下もご興味があるかもしれません:
  • 少なくともn日間連続してログインしているユーザーに対するSQLクエリ
  • MySQLはすべてのカテゴリの最初のNレコードを取得します
  • MySQL で n 回以上連続して出現する数字を見つける方法

<<:  JavaScript でプロパティハイジャックを実装する方法 defineProperty

>>:  Centos8 でローカル Web サーバーを構築するための実装手順

推薦する

MySQLログシステムの使い方に関する簡単なチュートリアル

目次序文1. エラーログ2. バイナリログ1. バイナリログを有効にする2. バイナリログ形式3. ...

ブラウザ内でHTMLタグを中央に配置するCSSスタイル

CSS スタイル:コードをコピーコードは次のとおりです。 <スタイル タイプ="te...

MySQLクエリトランザクション処理へのノード接続の実装

目次トピックmysqlの追加、削除、変更、クエリを入力しますMySQL トランザクション処理私は M...

MySQL の大文字と小文字の区別に関する注意

目次MySQLの大文字と小文字の区別はパラメータによって制御されますMySQLの大文字と小文字の区別...

1つのコマンドで、シェルの読み取りコマンドの共通パラメータを理解できます。

Shell で受信パラメータを受信する方法は 2 つあることがわかっています。 1 つはスクリプト...

Linux システムで IPv6 をサポートするように Nginx を設定する方法

1. 既存のnginxがipv6をサポートしているかどうかを確認する既存の nginx が ipv6...

Linux で time(NULL) 関数と localtime() を使用して現在の時刻を取得する方法

time(); 関数関数プロトタイプ: time_t time(time_t *timer)関数の目...

MySQL の永続性とロールバックの原理を 1 つの記事で理解する

目次再実行ログディスクデータを直接更新するのではなく、最初にメモリデータを更新する必要があるのはなぜ...

Linux システムで crontab を使用して MySQL データベースを定期的にバックアップする方法

システムの crontab を使用して定期的にバックアップ ファイルを実行し、バックアップ結果を日付...

MySQLの整数データ型tinyintの詳細な説明

目次1.1Tinyint型の説明1.2 練習環境の説明1.3 未署名属性の追加1.3.1 SQLモー...

MySQL のインデックスとデータ テーブルを管理する方法

目次テーブルの競合を見つけて修正するインデックス統計の更新テーブルの競合を見つけて修正するデータ テ...

vue-pdf はオンラインファイルプレビューを実現します

この記事では、参考までに、ファイルのオンラインプレビューを実現するためのvue-pdfの具体的なコー...

Linux と Windows でスケジュールされたタスクを設定する方法

目次リナックス1. crontabの基本的な使い方2. ログを有効にする3. スケジュールされたタス...

MySQL 8.0.12 のインストールと設定のチュートリアル

この記事はMySQL 8.0.12のインストールと設定に関する詳細なチュートリアルを記録しています。...

コンパイル/サーバーなしでブラウザにCommonJSモジュールを実装する

目次導入1. one-click.jsとは2. パッケージングツールはどのように機能しますか? 3....