一般的なエラーのSQLの使用法は、あなたはそれをキャッチ?

1、LIMIT文

ページングクエリは、最も頻繁に使用されるシーンの一つですが、また、通常、最も問題の領域。次のような簡単な声明については、一般的なアプローチは、タイプ、名前、CREATE_TIMEフィールドプラス複合インデックスにDBAを考えることです。このような条件は、効果的にパフォーマンスを高めるために、インデックスをソートするために使用することができます。

SELECT * FROM操作WHERE   タイプ= 'SQLSTATS'       と名前= 'SlowLog' CREATE_TIMEのLIMIT 1000年、10 BY ORDER。

さて、多分DBAの90%以上が、これまでに問題を解決します。LIMIT句は「LIMITの1000000,10」になったときには、プログラマはまだ文句を言うだろう:私はなぜ10個のレコードを取得したり、遅く?

データベースは、記事に開始する場所から100万件のレコードを知らない知っているために、また、あったとしても、再びゼロから指数を計算する必要があります。このパフォーマンスの問題は、ほとんどの場合、怠惰なプログラマです。

フロントエンド、または他のシーンをエクスポートするデータの大規模なバッチ内のページデータを参照し、最大値は、クエリとして前のパラメータようなものであってもよいです。次のようにSQLを再設計しました:

image.png

ていないデータの量を持つ新しいデザインで固定し、基本的なクエリ時間は、成長と変化。

図2に示すように、暗黙的な変換

型の不一致定義されたSQL文のクエリ変数とフィールドは、他の一般的な間違いです。たとえば、次の文:

MySQLは> * SELECT延長説明       
          my_balance Bから>       
          b.bpn = 14000000123>       
          >とb.isverifiedはNULLです。
MySQLの>ショー警告。
| 警告| 1739 | 「field'bpn上index'bpn'due totypeor照合変換に参照アクセスを使用することはできません

前記BPN定義フィールドはvarchar(20)は、MySQL、デジタルに変換し、次いで戦略比較文字列として。テーブルのフィールドに適用される機能は、失敗をインデックス。

上記のアプリケーションフレームワークではなく、プログラマの意図よりも、自動的にパラメータ充填してもよいです。今、非常に複雑なアプリケーションフレームワークの多くは、使いやすいだけでなく、それは掘り自分自身を与えるかもしれないように注意してください。

3、関連の更新、削除します

MySQL5.6が物理的および化学的性質の導入が、それは現在、クエリステートメントを最適化するための特別な注意が必要です。手動で書き換えJOINを更新または削除する必要があるため。

たとえば、次のUPDATE文、MySQLは実際の実装サイクル/ネストされたサブクエリ(DEPENDENT SUBQUERY)で、実行時間を想像することができます。

image.png

実施計画:

+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| id | select_type        | table |type| possible_keys | key    | key_len | ref  | rows | Extra                                              |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY            | o    | index |              | PRIMARY | 8      |      | 24  | Usingwhere; Using temporary                        |
| 2  | DEPENDENT SUBQUERY |      |      |              |        |        |      |      | Impossible WHERE noticed after reading const tables |
| 3  | DERIVED            | o    | ref  | idx_2,idx_5  | idx_5  | 8      | const | 1    | Usingwhere; Using filesort                        |
+----+--------------------+-------+-------+---------------+---------+---------+-------+------+-----------------------------------------------------+

重写为 JOIN 之后,子查询的选择模式从 DEPENDENT SUBQUERY 变成 DERIVED,执行速度大大加快,从7秒降低到2毫秒。

image.png

执行计划简化为:

+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| id | select_type | table |type| possible_keys | key  | key_len | ref  | rows | Extra                                              |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+
| 1  | PRIMARY    |      |      |              |      |        |      |      | Impossible WHERE noticed after reading const tables |
| 2  | DERIVED    | o    | ref  | idx_2,idx_5  | idx_5 | 8      | const | 1    | Usingwhere; Using filesort                        |
+----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------------------------------+

4、混合排序

MySQL 不能利用索引进行混合排序。但在某些场景,还是有机会使用特殊方法提升性能的。

image.png

执行计划显示为全表扫描:

+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
| id | select_type | table |type| possible_keys    | key    | key_len | ref      | rows    | Extra    
+----+-------------+-------+--------+-------------+---------+---------+---------------+---------+-+
|  1 | SIMPLE      | a    | ALL    | idx_orderid | NULL    | NULL    | NULL    | 1967647 | Using filesort |
|  1 | SIMPLE      | o    | eq_ref | PRIMARY    | PRIMARY | 122    | a.orderid |      1 | NULL          |
+----+-------------+-------+--------+---------+---------+---------+-----------------+---------+-+

由于 is_reply 只有0和1两种状态,我们按照下面的方法重写后,执行时间从1.58秒降低到2毫秒。

image.png

5、EXISTS语句

MySQL 对待 EXISTS 子句时,仍然采用嵌套子查询的执行方式。如下面的 SQL 语句:

image.png

执行计划为:

+----+--------------------+-------+------+-----+------------------------------------------+---------+-------+---------+ -----+
| id | select_type        | table |type| possible_keys    | key  | key_len | ref  | rows    | Extra  |
+----+--------------------+-------+------+ -----+------------------------------------------+---------+-------+---------+ -----+
|  1 | PRIMARY            | n    | ALL  |  | NULL    | NULL    | NULL  | 1086041 | Usingwhere|
|  1 | PRIMARY            | sra  | ref  |  | idx_user_id | 123    | const |      1 | Usingwhere|
|  2 | DEPENDENT SUBQUERY | m    | ref  |  | idx_message_info  | 122    | const |      1 | Using index condition; Usingwhere|
+----+--------------------+-------+------+ -----+------------------------------------------+---------+----

去掉 exists 更改为 join,能够避免嵌套子查询,将执行时间从1.93秒降低为1毫秒。

image.png

新的执行计划:

+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+
| id | select_type | table |type| possible_keys    | key      | key_len | ref  | rows | Extra                |
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+------+ -----+
|  1 | SIMPLE      | m    | ref    | | idx_message_info  | 122    | const    |    1 | Using index condition |
|  1 | SIMPLE      | n    | eq_ref | | PRIMARY  | 122    | ighbor_id |    1 | Usingwhere|
|  1 | SIMPLE      | sra  | ref    | | idx_user_id | 123    | const    |    1 | Usingwhere|
+----+-------------+-------+--------+ -----+------------------------------------------+---------+ -----+

6、条件下推

外部查询条件不能够下推到复杂的视图或子查询的情况有:

聚合子查询;

含有 LIMIT 的子查询;

UNION 或 UNION ALL 子查询;

输出字段中的子查询;

如下面的语句,从执行计划可以看出其条件作用于聚合子查询之后:

image.png

确定从语义上查询条件可以直接下推后,重写如下:

image.png

执行计划变为:

+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+
| id | select_type | table |type| possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+
| 1 | SIMPLE | operation | ref | idx_4 | idx_4 | 514 | const | 1 | Usingwhere; Using index |
+----+-------------+-----------+------+---------------+-------+---------+-------+------+--------------------+

7、提前缩小范围

先上初始 SQL 语句:

image.png

该SQL语句原意是:先做一系列的左连接,然后排序取前15条记录。从执行计划也可以看出,最后一步估算排序记录数为90万,时间消耗为12秒。

+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+
| id | select_type | table |type| possible_keys | key    | key_len | ref            | rows  | Extra                                              |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+
|  1 | SIMPLE      | o    | ALL    | NULL          | NULL    | NULL    | NULL            | 909119 | Usingwhere; Using temporary; Using filesort      |
|  1 | SIMPLE      | u    | eq_ref | PRIMARY      | PRIMARY | 4      | o.uid |      1 | NULL                                              |
|  1 | SIMPLE      | p    | ALL    | PRIMARY      | NULL    | NULL    | NULL            |      6 | Usingwhere; Using join buffer (Block Nested Loop) |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------+----------------------------------------------------+

由于最后 WHERE 条件以及排序均针对最左主表,因此可以先对 my_order 排序提前缩小数据量再做左连接。SQL 重写后如下,执行时间缩小为1毫秒左右。

image.png

再检查执行计划:子查询物化后(select_type=DERIVED)参与 JOIN。虽然估算行扫描仍然为90万,但是利用了索引以及 LIMIT 子句后,实际执行时间变得很小。复制代码

+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+
| id | select_type | table      |type| possible_keys | key    | key_len | ref  | rows  | Extra                                              |
+----+-------------+------------+--------+---------------+---------+---------+-------+--------+----------------------------------------------------+
|  1 | PRIMARY    | | ALL    | NULL          | NULL    | NULL    | NULL  |    15 | Using temporary; Using filesort                    |
|  1 | PRIMARY    | u          | eq_ref | PRIMARY      | PRIMARY | 4      | o.uid |      1 | NULL                                              |
|  1 | PRIMARY    | p          | ALL    | PRIMARY      | NULL    | NULL    | NULL  |      6 | Usingwhere; Using join buffer (Block Nested Loop) |
| 2 | 派生| O | インデックス| NULL | idx_1 | 5 | NULL | 909112 | Usingwhere | 
+ ---- + ------------- + ------------ + -------- + -------- ------- + --------- + --------- + ------- + -------- + ----- ----------------------------------------------- +

8、中間結果は、プッシュダウンを設定します

例(左メインテーブルには優先行動クエリで参加)以下を見ては、当初、最適化されています:

image.png

他の問題があるように声明?Cは、テーブル全体のサブクエリは、文全体のパフォーマンスが低下につながるテーブルの状況の特に多数で、クエリを集約見ることは難しいことではありません。

実際には、サブクエリcに対して、接続データの最終的な結果は、メインテーブルにのみ関心を設定することができ、RESOURCEIDを一致させることができ、左。したがって、我々は次の文を書き換えることができ、実行時間は2秒に、元の2ミリ秒から減少しました。

image.png

しかし、サブクエリは、私たちのSQL文で複数回表示されます。このようなアプローチだけでなく、追加費用なく、かなりの複雑全体の声明を出します。WITHステートメントを使用してもう一度書き直し:

image.png

概要

データベースのコンパイラは、SQLの実際の実装を決定し、実行計画を生成します。しかし、コンパイラは、単にサービスをしようと、すべてのデータベースのコンパイラは、完璧ではありません。

上記シーンのほとんどは、他のデータベースでのパフォーマンス上の問題があります。データベースのコンパイラ機能、高性能なSQL文を書くための規制を回避するために、その弱点をご覧ください。

データモデルの設計でプログラマやSQL文、考えや意識のアルゴリズムを書くに提起しなければなりません。

WITHステートメントを使用しての習慣を開発するために、複雑なSQL文を書きます。SQL文の簡潔かつ明確な思考は、データベースの負担を軽減することができます。


おすすめ

転載: blog.51cto.com/14453419/2422359