ホームページ  >  記事  >  データベース  >  SQLクエリステートメントがどのように実行されるかを分析する

SQLクエリステートメントがどのように実行されるかを分析する

王林
王林転載
2020-01-30 20:58:262200ブラウズ

SQLクエリステートメントがどのように実行されるかを分析する

最初に、id フィールドを持つ user_info テーブルがあります。次のクエリ ステートメントを実行します:

select * from user_info where id = 1;

戻り結果は次のとおりです:

SQLクエリステートメントがどのように実行されるかを分析する

Mysql の基本アーキテクチャ図:

SQLクエリステートメントがどのように実行されるかを分析する

(関連ビデオ チュートリアルの推奨事項: mysql ビデオ チュートリアル)

一般的に言えば, MySQL はサーバー層とストレージエンジン層の 2 つの部分に分かれています。

サーバー層には、コネクタ、クエリ キャッシュ、アナライザー、エグゼキューターなどに加え、すべての組み込み関数 (日付、時刻、計​​算関数、暗号化関数など) およびクロスストレージ エンジンが含まれます。関数 (ストアド プロシージャ、トリガー、ビューなど)。

ストレージ エンジン層はデータの保存と取得を担当し、InnoDB、MyISAM、Memory などの複数のストレージ エンジンをサポートします。 MySQL 5.5.5 以降のデフォルトのストレージ エンジンは InnoDB です。

コネクタ

SQL ステートメントをクエリする前に、まず MySQL との接続を確立する必要があります。これはコネクタによって行われます。コネクタは、クライアントとの接続の確立、権限の取得、接続の維持および管理を担当します。接続コマンドは次のとおりです:

mysql -h$ip -P$port -u$user -p

パスワードを入力してください。検証に合格した後、コネクタは権限テーブルに移動して、ユーザーが持っている権限を確認します。その後、この接続の権限判断ロジックは次のようになります。アクセス許可: ユーザーが接続を正常に確立した後、管理者がユーザーのアクセス許可を変更しても、既存の接続のアクセス許可には影響しません。変更後は、新しい接続のみが新しいアクセス許可設定を使用します。 。

接続が完了した後、後続のアクションがない場合、接続はアイドル状態になります。これは show processlist コマンドで確認できます。結果は次のとおりです:

SQLクエリステートメントがどのように実行されるかを分析する

クライアントが非アクティブな時間が長すぎる場合、コネクタはクライアントを自動的に切断します。この時間はパラメータ wait_timeout とデフォルト値によって制御されます。は8時間です。接続が切断された後にクライアントが再度リクエストを送信すると、次のエラー リマインダーが表示されます: クエリ中に MySQL サーバーへの接続が失われました

長い接続と短い接続

#データベースにおいて、長い接続とは、接続が成功した後、クライアントがリクエストを継続する場合、常に同じ接続が使用されることを意味します。短い接続とは、いくつかのクエリが実行された後に接続が切断され、次のクエリのために新しい接続が再確立されることを意味します。

接続を確立するプロセスは通常複雑であるため、使用中の接続を確立するアクションを最小限に抑え、長い接続を使用することをお勧めします。ただし、MySQL が実行中に一時的に使用するメモリは接続オブジェクトで管理されるため、長い接続をすべて使用した後、MySQL が占有するメモリが急速に増加することがあります。

これらのリソースは、接続が切断されると解放されます。そのため、長時間の接続が蓄積すると、メモリを占有しすぎてシステムによって強制終了 (OOM) される可能性があり、現象から判断すると MySQL が異常再起動します。

この問題を解決するにはどうすればよいですか?次の 2 つの解決策を検討できます。

長い接続を定期的に切断します。一定期間使用した後、またはメモリを消費する大規模なクエリが実行されたとプログラムが判断した後、接続は切断され、クエリが必要になってから再接続されます。 MySQL 5.7 以降の場合、比較的大規模なオペレーションを実行するたびに mysql_reset_connection を実行することで接続リソースを再初期化できます。このプロセスでは再接続や権限の確認は必要ありませんが、接続は作成されたばかりの状態に復元されます。

クエリ キャッシュ

接続が確立された後、select ステートメントの実行が開始されます。実行前に、まずキャッシュがクエリされます。

MySQL はクエリ リクエストを取得した後、まずキャッシュにクエリを実行して、このステートメントが実行されたかどうかを確認します。実行されたステートメントとその結果は、キーと値のペアの形式で特定のメモリ領域に保存されます。キーはクエリ ステートメントであり、値はクエリ結果です。クエリがこのキャッシュ内で直接キーを見つけることができた場合、
値がクライアントに直接返されます。

ステートメントがクエリ キャッシュにない場合は、後続の実行フェーズが続行されます。実行が完了すると、実行結果はクエリ キャッシュに保存されます。クエリがキャッシュにヒットした場合、MySQL は後続の複雑な操作を実行せずに結果を直接返すことができるため、効率が向上します。

但是查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。对于更新压力大的数据库来说,查询缓存的命中率会非常低。如果业务中需要有一张静态表,很长时间才会更新一次。

比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。MySQL 提供了这种按需使用的方式。可以将参数 query_cache_type 设置成 DEMAND,对于默认的 SQL 语句都将不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定,如下:

mysql> select SQL_CACHE * from user_info where id = 1;

MySQL 8.0 版本将查询缓存的功能删除了。

分析器(Analyzer)

如果查询缓存未命中,就要开始执行语句了。首先,MySQL 需要对 SQL 语句进行解析。

分析器先会做词法分析。SQL 语句是由多个字符串和空格组成的,MySQL 需要识别出里面的字符串分别是什么,代表什么。MySQL 从你输入的 select 这个关键字识别出来,这是查询语句。它也要把字符串 user_info 识别成表名,把字符串 id 识别成列名。之后就要做语法分析。根据词法分析的结果,语法分析器会根据语法规则,判断输入的 SQL 语句是否满足 MySQL 语法。

如果你 SQL 语句不对,就会收到 You have an error in your SQL syntax 的错误提醒,比如下面这个语句 from 写成了 form。

mysql> select * form user_info  where id = 1;
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'form user_info  where id = 1' at line 1

一般语法错误会提示第一个出现错误的位置,所以要关注的是紧接 use near 的内容。

优化器(Optimizer)

经过分析器的词法分析和语法分析后,还要经过优化器的处理。

优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的 join:

mysql> SELECT * FROM order_master JOIN order_detail USING (order_id) WHERE order_master.pay_status = 0 AND order_detail.detail_id = 1558963262141624521;

既可以先从表 order_master 里面取出 pay_status = 0 的记录的 order_id 值,再根据 order_id 值关联到表 order_detail,再判断 order_detail 里面 detail_id 的值是否等于 1558963262141624521。

也可以先从表 order_detail 里面取出 detail_id = 1558963262141624521 的记录的 order_id 值,再根据 order_id 值关联到 order_master,再判断 order_master 里面 pay_status 的值是否等于 0。

这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。优化器阶段完成后,这个语句的执行方案就确定下来了,然后进入执行器阶段。

执行器(Actuator)

MySQL 通过分析器知道了要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。

开始执行的时候,要先判断一下你对这个表 user_info 有没有执行查询的权限,如果没有,就会返回没有权限的错误,如下所示 (如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证。查询也会在优化器之前调用 precheck 验证权限)。

mysql> select * from user_info where id = 1;ERROR 1142 (42000): SELECT command denied to user 'wupx'@'localhost' for table 'user_info'

如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。比如我们这个例子中的表 user_info 中,id 字段没有索引,那么执行器的执行流程是这样的:

1、调用 InnoDB 引擎接口取这个表的第一行,判断 id 值是不是 1,如果不是则跳过,如果是则将这行存在结果集中;

2、调用引擎接口取下一行,重复相同的判断逻辑,直到取到这个表的最后一行。

3、执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。

对于有索引的表,第一次调用的是取满足条件的第一行这个接口,之后循环取满足条件的下一行这个接口。

数据库的慢查询日志中有 rows_examined 字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。

总结

主要通过对一个 SQL 语句完整执行过程进行讲解,介绍 MySQL 的逻辑架构,MySQL 主要包括连接器、查询缓存、分析器、优化器、执行器这几个模块。

相关文章教程推荐:mysql教程

以上がSQLクエリステートメントがどのように実行されるかを分析するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
前の記事:mysql分離レベル次の記事:mysql分離レベル