データベース設計で考慮すべき問題
インデックスを使用する理由
- データをすばやくクエリする
インデックスデータ構造
- 二分探索のための二分探索木を構築する
- 検索用のBTree構造を確立します
- 検索するB +ツリー構造を確立する
- 検索用のハッシュ構造を確立する
BTree
- ルートノードには、少なくとも2つの子が含まれます
- ツリーの各ノードには、最大m個の子が含まれます
- ルートノードとリーフノードを除いて、他のすべてのノードには少なくともceil(m / 2)の子があります
- すべてのリーフノードは同じレイヤー上にあります
B +ツリー
- 非リーフノードのサブツリーポインタの数は、キーワードの数と同じです。
- 非リーフノードのサブツリーポインタp [i]は、キー値[k [i]、k [i + 1])のサブツリーを指します。
- 非リーフノードはインデックス作成にのみ使用され、データはリーフノードに保存されます
- すべてのリーフノードには、次のリーフノードを指すチェーンポインタがあります
B + Treeはストレージインデックスに適しています
- B +ツリーのディスク読み取りおよび書き込みコストは低くなります(データはリーフノードにのみ保存されるため、ディスクIOを削減できます)
- B +ツリークエリの効率はより安定しています
- B +ツリーは、データベースのスキャンに役立ちます
ハッシュインデックス
クエリ速度は理論的にはB + Treeよりも高速です。
短所:
- 会うためだけに
=
、in
範囲クエリを使用することませんは - データの並べ替え操作を回避するために使用することはできません
- インデックスキーの一部を使用してクエリを実行することはできません
- 多数のハッシュ衝突が発生したため、パフォーマンスは必ずしもBTreeよりも高いとは限りません。
密インデックスと疎インデックスの違い
密なインデックスリーフノードは、キー値だけでなく、同じ行の他の列の情報も保存します。密なインデックスは、テーブルの物理的な並べ替え順序も決定します。テーブルは1つの物理ソート順しか持てないため、テーブルは1つの密なインデックスしか持てません。
スパースインデックスリーフノードはキー情報とプライマリキー情報のみを保存し、データはプライマリキーインデックスを介してクエリする必要があります。
InnoDB
- 主キーが定義されている場合、主キーは密なインデックスとして使用されます
- 主キーが定義されていない場合、テーブルの最初の一意の空でないインデックスが密なインデックスとして使用されます
- 上記の条件が満たされない場合、Innodbは非表示の主キー(密なインデックス)を生成します
- 非主キーインデックスは、2つのルックアップを含む、関連するキービットとそれに対応する主キー値を格納します
遅いクエリSQLを見つけて最適化する方法
- 遅いログに基づいて遅いクエリSQLを見つけます
- Explainおよびその他のツールを使用してSQLを分析する
- SQLを変更するか、SQLにインデックスを取得させてみてください
遅いログに関連する構成情報を照会します(mysql 8.0.xに基づく)
SHOW VARIABLES LIKE '%query%'
結果は以下のとおりです。
Variable_name Value
---------------------------- -------------------------------------------------
binlog_rows_query_log_events OFF
ft_query_expansion_limit 20
have_query_cache NO
long_query_time 1.000000
query_alloc_block_size 8192
query_prealloc_size 8192
slow_query_log ON
slow_query_log_file /var/lib/mysql/izwz99rnmfr0cdntpgsfr9z-slow.log
slow_query_log
ONは、低速ログがオンになっていることを意味します。
slow_query_log_file
低速ログファイルのパスは、
long_query_time
低速SQLと見なされる期間をマイクロ秒(us)で意味します。1.000000us= 1s
スロークエリログをオンにします
。slow_query_logがオフの場合、スローログはオンになりません。次のように開くことができます。
SET GLOBAL slow_query_log = ON
遅いクエリの場合、変更には時間がかかると見なされます
SET GLOBAL long_query_time = 1; #单位1s
SET GLOBAL long_query_time = 0.8; #单位0.8s = 800ms
変更後、クライアントは再接続して有効にし、変更された結果を表示する必要があります。mysqlの再起動後、デフォルト値が復元されます。mysql構成ファイルを変更することで永続的に有効にできます
カウントされた遅いクエリの数をクエリする
SHOW STATUS LIKE '%slow_queries%'
現在の接続の遅いクエリの数を表示するだけで、再接続すると0に戻ります
mysqlサーバーで遅いログファイルを表示する
# Time: 2021-02-22T13:39:46.688722Z
# User@Host: root[root] @ [139.226.12.65] Id: 201
# Query_time: 1.006213 Lock_time: 0.195229 Rows_sent: 0 Rows_examined: 0
use lwl_registry;
SET timestamp=1614001185;
select * from order_info where pwd = '122'
Query_timeは、このクエリに時間がかかります
explain
SQLステートメントを分析することによって
Explainを通じて、SQLがインデックスを使用したかどうかを確認できます
EXPLAIN SELECT * FROM order_info WHERE username = '122'
結果は以下のとおりです。
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
------ ----------- ---------- ---------- ------ ------------- ------ ------- ------ ------ -------- -------------
1 SIMPLE order_info (NULL) ALL (NULL) (NULL) (NULL) (NULL) 360772 10.00 Using where
type
:、ソート・パフォーマンス・データ行を見つける方法それ降順に順位を:
system
> const
> eq_ref
> ref
> fulltext
> ref_or_null
> index_merge
> unique_subquery
> index_subquery
> range
> index
>all
index
そして、all
このクエリが全表スキャンを実行していることを表します。遅いクエリのEXPLAINステートメントがこれら2つの値の結果である場合は、最適化を検討する必要があります。
Extra
:次の2つの項目の値が表示される場合は、mysqlがインデックスをまったく使用していないことを意味し、最適化を検討する必要があります
追加の価値 | 説明 |
---|---|
filesortの使用 | MySQLは、メモリ内またはディスク上で並べ替えられる可能性のあるインデックスに従ってテーブルから関連するコンテンツを順番に読み取るのではなく、外部インデックスを使用して結果を並べ替えることを意味します。 MySQLのインデックスを使用して実行できない並べ替え操作は、ファイルの並べ替えと呼ばれます |
一時的な使用 | mysqがクエリ結果を並べ替えるときに一時テーブルを使用することを示します。order by クエリの並べ替えとグループ化で一般的に使用されgroup by ます。 |
一般的な最適化ソリューション:
- ビジネスで許可されている場合は、既存のインデックスフィールドを使用してクエリを実行できます。
- インデックスを適切に追加する
alter table order_info add index idx_name(username)
- インデックスフィールドで並べ替え
- 概要インデックス
MySQLのインデックスは、以下の演算子のためにのみ使用し<
、<=
、=
、>=
、between and
、like 非%开头
インデックスを使用し、in
行かないかもしれないインデックスを取るかもしれないが、!=
各テーブルには16個のインデックスを作成することができ、理論的には、インデックスを取ることはありません。 - MySQLは、「
允许
null isnull列也加上索引,但只会对
」のクエリ条件で有効になります
質問:InnoDBのテーブルにidプライマリキーインデックスがあり、空ではない一意のインデックスsessionIdがある場合、count(id)でデータ項目の数をカウントするときに使用されるインデックスフィールドはどれですか?
EXPLAIN SELECT COUNT(id) FROM `client`
回答:空ではない一意のインデックスsessionIdが使用され、結果は次のようになります。
理由: InnoDBの主キーで使用されるクラスター化インデックスであるリーフノードに他の列が含まれているため、クエリオプティマイザーが最適なインデックスを選択します。データ、あなたはもっと読む必要がありますデータ。sessionIdは空ではなく、非クラスター化インデックスであり、インデックスフィールドと主キーのみが含まれ、データ量が少なく、読み取りが高速です。
インデックスの取得を強制
where条件がある場合、条件内のインデックスが使用されます
SELECT COUNT(id) FROM `client` WHERE id = 39 #走主键索引
SELECT COUNT(id) FROM `client` WHERE session_id = 1427325133344736216 #走唯一索引
ジョイント(結合)インデックスの左端の一致原理の理由
- コンポジットインデックス、左端の費用収益対応の原則それが範囲クエリを(遭遇するまで、MySQLは常に右側に照合されます
>
、、 、)試合を停止します。たとえば、複合インデックス(a、b、c、d)のクエリ条件が使用されている場合、インデックスはdに使用されません。<
between
like
where a=3 and b=4 and c>5 and d = 6
=
またin
、たとえば、where a=3 and c=5 and b=4
クエリシーケンスabcが条件ではない場合でも、クエリの組み合わせインデックス(a、b、c)が故障している可能性がありますが、クエリオプティマイザの最適化後、インデックスは実行できますがwhere c=5 and b=4
、左端を満たしていません。一致、インデックスを取得できません
左端の一致原則の理由: 2番目のフィールドの並べ替えは最初のフィールドに基づいているため、2番目のフィールドだけでは順序が狂っています。
できるだけ多くのインデックスを作成する方が良いですか?
- データ量が少ないテーブルにはインデックスを付ける必要がなく、インデックスを付けると追加のインデックスオーバーヘッドが増加します
- データの変更はインデックスを維持する必要があるため、インデックスが多いほどメンテナンスコストが高くなります
- より多くのインデックスは、多くのスペースが必要であることを意味します