MySQL ではどのようにしてインデックス作成を効率化できるのでしょうか?
データベース シリーズが更新されたので、皆さんはすべての概念を大まかに理解していると思います。今週コメントを読んでいたときに、非常に興味深いネチズンの質問を見つけました。「インデックスを設計するにはどうすればよいですか?」インデックスはどのように設計しますか?より効率的に設計するにはどうすればよいでしょうか?
まえがき
インデックスはリンク リストに基づいたツリー状のツリー構造であり、データを迅速に取得できることがわかっています。 RDBMS データベースはこれを実装しており、MySQL の B Tree インデックス、MongoDB の BTree インデックスなどのインデックス機能を備えています。
業務開発の過程において、インデックス設計が効率的であるか否かは、インターフェースに対応するSQLの実行効率を左右し、インデックスが効率的であればインターフェースの応答時間も短縮され、コストも削減できます。私たちの現実的な目標は、インデックス設計 -> インターフェースの応答時間の削減 -> サーバー構成の削減 -> コストの削減です。上司はコストを最も懸念しているため、最終的にはコストで実装する必要があります。
今日は、MySQL のインデックスとインデックスの設計方法についてお話します。インデックスを使用することによってのみ、下位インターフェイスの RT を改善し、ユーザーの健康を改善することができます。
MySQL のインデックス
MySQL の InnoDB エンジンは、B ツリー構造を使用してインデックスを保存し、データ クエリ中のディスク IO の数を最小限に抑えることができます。ツリーはクエリのパフォーマンスに直接影響し、通常、ツリーの高さは 3 ~ 4 層に維持されます。
B ツリーはルート、ブランチ、リーフの 3 つの部分で構成されます。ルートとブランチにはデータは格納されず、ポインタ アドレスのみが格納されます。すべてのデータはリーフ ノードに格納され、ノード間では双方向リンク リストが使用されます。リーフ ノード。リンク、構造は次のとおりです:
上記からわかるように、各リーフ ノードは 3 つの部分、つまり先行ポインタ p_prev、data で構成されます。 dataと後続ポインタp_next、while data データは順番に並んでいます。デフォルトは昇順のASCです。Bツリーの右側に分布するキー値は常に左側よりも大きくなります。同時に、データからの距離も離されます。各リーフへのルートは等しい、つまり、どのリーフ ノードへのアクセスに必要な IO も同じ、つまり、インデックス ツリーの高さはレベル 1 IO 操作です。
MySQL のインデックスは、ディスク領域を占有する小さなテーブルと考えることができます。インデックスを作成するプロセスは、実際には、インデックス列に従ってソートするプロセスです。まず、sort_buffer_size でソートします。ソートするデータが大きい場合、sort_buffer_size の容量に達しない場合は、一時ファイルを使用してソートする必要がありますが、最も重要なことは、ソート操作 (distinct、group by、order by) がインデックス作成によって回避できることです。
クラスタードインデックス
MySQLのテーブルはIOT(Index Organization Table、インデックス組織テーブル)であり、データは主キーID順(論理的に連続、物理的に不連続)に格納されます。主キー ID は、データの行全体を格納するクラスター化インデックスです。明示的に主キーが指定されていない場合、MySQL はすべてのカラムを結合して主キーとして row_id を構築します (テーブル ユーザー (id、user_id、 user_name、phone、主キー(id))、id はクラスター化インデックスであり、データ id、user_id、user_name、phone の行全体が格納されます。
補助インデックス
補助インデックスはセカンダリ インデックスとも呼ばれ、インデックス列の保存に加えて、主キー ID も保存されます。 user_name のインデックス idx_user_name(user_name) に関しては、実際には idx_user_name(user_name, id) と同等です。MySQL は補助インデックスの最後に主キー ID を自動的に追加します。Oracle データベースに精通している人なら誰でもそれを知っています。インデックス列、インデックスには row_id も格納されます (データを表す物理的な場所は、オブジェクト番号、データ ファイル番号、データ ブロック番号、データ行番号の 4 つの部分で構成されます)。また、補助インデックスを作成するときに主キー ID を表示することもできます。
-- 创建user_name列上的索引 mysql> create index idx_user_name on users(user_name); -- 显示添加主键id创建索引 mysql> create index idx_user_name_id on users(user_name,id); -- 对比两个索引的统计数据 mysql> select a.space as tbl_spaceid, a.table_id, a.name as table_name, row_format, space_type, b.index_id , b.name as index_name, n_fields, page_no, b.type as index_type from information_schema.INNODB_TABLES a left join information_schema.INNODB_INDEXES b on a.table_id =b.table_id where a.name = 'test/users'; +-------------+----------+------------+------------+------------+----------+------------------+----------+------ | tbl_spaceid | table_id | table_name | row_format | space_type | index_id | index_name | n_fields | page_no | index_type | +-------------+----------+------------+------------+------------+----------+------------------+----------+------ | 518 | 1586 | test/users | Dynamic | Single | 1254 | PRIMARY | 9 | 4 | 3 | | 518 | 1586 | test/users | Dynamic | Single | 4003 | idx_user_name | 2 | 5 | 0 | | 518 | 1586 | test/users | Dynamic | Single | 4004 | idx_user_name_id | 2 | 45 | 0 | mysql> select index_name, last_update, stat_name, stat_value, stat_description from mysql.innodb_index_stats where index_name in ('idx_user_name','idx_user_name_id'); +------------------+---------------------+--------------+------------+-----------------------------------+ | index_name | last_update | stat_name | stat_value | stat_description | +------------------+---------------------+--------------+------------+-----------------------------------+ | idx_user_name | 2021-01-02 17:14:48 | n_leaf_pages | 1358 | Number of leaf pages in the index | | idx_user_name | 2021-01-02 17:14:48 | size | 1572 | Number of pages in the index | | idx_user_name_id | 2021-01-02 17:14:48 | n_leaf_pages | 1358 | Number of leaf pages in the index | | idx_user_name_id | 2021-01-02 17:14:48 | size | 1572 | Number of pages in the index |
2 つのインデックスの結果を比較します。n_fields はインデックス内の列数を表し、n_leaf_pages はインデックス内のリーフ ページ数を表し、size はインデックス内の合計ページ数を表します。データ比較を通じてこれを確認してください。補助インデックスには主キー ID が含まれており、これは 2 つのインデックスが完全に一貫していることも示しています。
n_fields | n_leaf_pages | size | |||
---|---|---|---|---|---|
#2 | 1358 | 1572 | |||
2 | 1358 | 1572 |
复合索引 | Type | Rows | 参与过滤索引列 | Chosen | Cause |
---|---|---|---|---|---|
idx_status_create_time | Index Range Scan | 98518 | status AND create_time | True | Cost低 |
idx_create_time_status | Index Range Scan | 98518 | create_time | False | Cost高 |
MySQL优化器是基于Cost的,COST主要包括IO_COST和CPU_COST,MySQL的CBO(Cost-Based Optimizer基于成本的优化器)总是选择Cost最小的作为最终的执行计划去执行,从上面的分析,CBO选择的是复合索引idx_status_create_time,因为该索引中的status和create_time都能参与了数据过滤,成本较低;而idx_create_time_status只有create_time参数数据过滤,status被忽略了,其实CBO将其简化为单列索引idx_create_time,选择性没有复合索引idx_status_create_time好。
复合索引设计原则
将范围查询的列放在复合索引的最后面,例如idx_status_create_time。
列过滤的频繁越高,选择性越好,应该作为复合索引的前导列,适用于等值查找,例如idx_user_id_status。
这两个原则不是矛盾的,而是相辅相成的。
跳跃索引
一般情况下,如果表users有复合索引idx_status_create_time,我们都知道,单独用create_time去查询,MySQL优化器是不走索引,所以还需要再创建一个单列索引idx_create_time。用过Oracle的同学都知道,是可以走索引跳跃扫描(Index Skip Scan),在MySQL 8.0也实现Oracle类似的索引跳跃扫描,在优化器选项也可以看到skip_scan=on。
| optimizer_switch |use_invisible_indexes=off,skip_scan=on,hash_join=on |
适合复合索引前导列唯一值少,后导列唯一值多的情况,如果前导列唯一值变多了,则MySQL CBO不会选择索引跳跃扫描,取决于索引列的数据分表情况。
mysql> explain select id, user_id,status, phone from users where create_time >='2021-01-02 23:01:00' and create_time <= '2021-01-03 23:01:00'; +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+---- | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+---- | 1 | SIMPLE | users | NULL | range | idx_status_create_time | idx_status_create_time | NULL | NULL | 15636 | 11.11 | Using where; Using index for skip scan|
也可以通过optimizer_switch='skip_scan=off’来关闭索引跳跃扫描特性。
总结
本位为大家介绍了MySQL中的索引,包括聚集索引和辅助索引,辅助索引包含了主键id用于回表操作,同时利用覆盖索引扫描可以更好的优化SQL。
同时也介绍了如何更好做MySQL索引设计,包括前缀索引,复合索引的顺序问题以及MySQL 8.0推出的索引跳跃扫描,我们都知道,索引可以加快数据的检索,减少IO开销,会占用磁盘空间,是一种用空间换时间的优化手段,同时更新操作会导致索引频繁的合并分裂,影响索引性能,在实际的业务开发中,如何根据业务场景去设计合适的索引是非常重要的,今天就聊这么多,希望对大家有所帮助。
相关推荐:《mysql教程》
以上がMySQL ではどのようにしてインデックス作成を効率化できるのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











ビッグ データ構造の処理スキル: チャンキング: データ セットを分割してチャンクに処理し、メモリ消費を削減します。ジェネレーター: データ セット全体をロードせずにデータ項目を 1 つずつ生成します。無制限のデータ セットに適しています。ストリーミング: ファイルやクエリ結果を 1 行ずつ読み取ります。大きなファイルやリモート データに適しています。外部ストレージ: 非常に大規模なデータ セットの場合は、データをデータベースまたは NoSQL に保存します。

MySQL クエリのパフォーマンスは、検索時間を線形の複雑さから対数の複雑さまで短縮するインデックスを構築することで最適化できます。 PreparedStatement を使用して SQL インジェクションを防止し、クエリのパフォーマンスを向上させます。クエリ結果を制限し、サーバーによって処理されるデータ量を削減します。適切な結合タイプの使用、インデックスの作成、サブクエリの使用の検討など、結合クエリを最適化します。クエリを分析してボトルネックを特定し、キャッシュを使用してデータベースの負荷を軽減し、オーバーヘッドを最小限に抑えます。

PHP で MySQL データベースをバックアップおよび復元するには、次の手順を実行します。 データベースをバックアップします。 mysqldump コマンドを使用して、データベースを SQL ファイルにダンプします。データベースの復元: mysql コマンドを使用して、SQL ファイルからデータベースを復元します。

MySQLテーブルにデータを挿入するにはどうすればよいですか?データベースに接続する: mysqli を使用してデータベースへの接続を確立します。 SQL クエリを準備します。挿入する列と値を指定する INSERT ステートメントを作成します。クエリの実行: query() メソッドを使用して挿入クエリを実行します。成功すると、確認メッセージが出力されます。

MySQL 8.4 (2024 年時点の最新の LTS リリース) で導入された主な変更の 1 つは、「MySQL Native Password」プラグインがデフォルトで有効ではなくなったことです。さらに、MySQL 9.0 ではこのプラグインが完全に削除されています。 この変更は PHP および他のアプリに影響します

PHP で MySQL ストアド プロシージャを使用するには: PDO または MySQLi 拡張機能を使用して、MySQL データベースに接続します。ストアド プロシージャを呼び出すステートメントを準備します。ストアド プロシージャを実行します。結果セットを処理します (ストアド プロシージャが結果を返す場合)。データベース接続を閉じます。

PHP を使用して MySQL テーブルを作成するには、次の手順が必要です。 データベースに接続します。データベースが存在しない場合は作成します。データベースを選択します。テーブルを作成します。クエリを実行します。接続を閉じます。

Oracle データベースと MySQL はどちらもリレーショナル モデルに基づいたデータベースですが、Oracle は互換性、スケーラビリティ、データ型、セキュリティの点で優れており、MySQL は速度と柔軟性に重点を置いており、小規模から中規模のデータ セットに適しています。 ① Oracle は幅広いデータ型を提供し、② 高度なセキュリティ機能を提供し、③ エンタープライズレベルのアプリケーションに適しています。① MySQL は NoSQL データ型をサポートし、② セキュリティ対策が少なく、③ 小規模から中規模のアプリケーションに適しています。
