Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

序文

最近、同社はコードレビュー中にDATE_FORMAT関数を使用する問題について異なる見解を持っていました。特定のDATE_FORMATはインデックスに影響しますか?どのような状況で影響がありますか?週末には何も起こらず、mysql実行計画による一連のテストが行​​われました。

説明分析を使用する

実行計画は、MysqlがEXPLAINを使用してSqlステートメントを実行する方法を示すことです。図に示すように、出力には、Sqlクエリの順序、インデックスを使用するかどうか、および使用されるインデックス情報が含まれます。

Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

id:クエリ内の選択操作テーブルの順序を示します。大きいものから順番に実行されます。

select_type:これは選択のタイプを表します。オプションの値は次のとおりです:SIMPLE(シンプル)

Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

type:この属性はアクセスのタイプを表し、多くのタイプのアクセスがあります。最も一般的なものには、ALL(フルテーブルスキャン)、index(インデックススキャン)、range(範囲スキャン)、ref(非一意のインデックススキャン)、eq_ref(一意のインデックススキャン)、(const)定数参照、アクセス速度は遅いものから速いものまであります。それらの中で:範囲(範囲)はとの間で一般的であり、この場合よりも大きい場合と小さい場合があります。ヒント:このプロパティを使用して、低速のSQLにインデックスが付けられているかどうか、およびどのインデックスが削除されているかを確認できます。

Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

table:ステートメントによって照会されたテーブルを表します

possible_keys:名前が示すように、この属性はクエリステートメント、取得できるインデックス(一部のフィールドのインデックスの名前など)を提供します。ここで提供されるのは参照のみであり、実際のインデックスではないため、possible_Keysはヌル、キーは空の現象です。

key:プライマリキーインデックス(PRIMARY)や自作インデックスの名前など、MySQLで実際に使用されているインデックスを表示します。

key_len:インデックスによって使用されるバイト数を示します。

ref:接続一致条件。プライマリキーインデックスが取得された場合、値は次のようになります。const、テーブル全体のスキャンの場合、null値です。

行:スキャンされた行の数、つまり、目標の行数を取得するためにスキャンする必要のある行の数。通常、返される行の数よりも多くなります。通常の状況では、行が小さいほど効率が高くなり、ほとんどのSQL最適化によってこの値のサイズが小さくなります。(注:理想的には、スキャンされた行の数は理論的には実際に返される行の数と同じですが、関連するクエリなど、この状況は非常に少なく、スキャンされた行の数は返される行の数よりも大幅に増加します)

追加:この属性は非常に重要です。この属性には、SQLを実行するときの実際の状況に関する情報が含まれます。上記のとおり、「using where」が使用されます。これは、whereでフィルタリングして得られる値を意味します。一般的に使用されるのは、「Usingtemporary」: 「filesortを使用する」一時テーブル:filesortを使用する

示されているテーブルステートメントとデータ挿入sql:

Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

検証が必要なパートナーがいる場合は、上記の図と一致するSQLも添付してください。

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  `birth_date` date NULL DEFAULT NULL,
  `is_delete` tinyint(1) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `name`(`name`) USING BTREE,
  INDEX `age`(`age`) USING BTREE,
  INDEX `birth_date`(`birth_date`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 22 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '小明1', 1, '2000-01-01', 0);
INSERT INTO `user` VALUES (2, '小明2', 2, '2001-01-02', 0);
INSERT INTO `user` VALUES (3, '小明3', 3, '2002-01-03', 0);
INSERT INTO `user` VALUES (4, '小明4', 4, '2003-01-04', 0);
INSERT INTO `user` VALUES (5, '小明5', 5, '2004-01-05', 0);
INSERT INTO `user` VALUES (6, '小明6', 6, '2005-01-06', 0);
INSERT INTO `user` VALUES (7, '小明7', 7, '2006-01-07', 0);
INSERT INTO `user` VALUES (8, '小明8', 8, '2007-01-08', 0);
INSERT INTO `user` VALUES (9, '小明9', 9, '2008-01-09', 0);
INSERT INTO `user` VALUES (10, '小明1', 10, '2009-01-10', 0);
INSERT INTO `user` VALUES (11, '小明11', 11, '2010-01-11', 0);
INSERT INTO `user` VALUES (12, '小明12', 12, '2011-01-12', 0);
INSERT INTO `user` VALUES (13, '小明13', 13, '2012-01-13', 0);
INSERT INTO `user` VALUES (14, '小明14', 14, '2013-01-14', 0);
INSERT INTO `user` VALUES (15, '小明15', 15, '2014-01-15', 0);
INSERT INTO `user` VALUES (16, '小明16', 16, '2015-01-16', 0);
INSERT INTO `user` VALUES (17, '小明17', 17, '2016-01-17', 0);
INSERT INTO `user` VALUES (18, '小明18', 18, '2017-01-18', 0);
INSERT INTO `user` VALUES (19, '小明19', 19, '2018-01-19', 0);
INSERT INTO `user` VALUES (20, '小明20', 20, '2019-01-20', 0);
INSERT INTO `user` VALUES (21, '小明21', 21, '2020-01-21', 0);

検証プロセス

注:この記事で使用されているデータベースはmysql:5.7.24です。

1.DATE_FORMAT関数はありません

最初の方法:

select * from user where birth_date <= '2009-10-10';

Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

キーは、上の図に示すように使用できます:birth_date。

2番目の方法:

EXPLAIN SELECT * FROM USER WHERE birth_date <= '2009-10-10'およびbirth_date> = '2009-10-10';

Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

キーは、上の図に示すように使用されます:birth_date。

2.DATE_FORMAT関数を使用します

最初の方法:

EXPLAIN
SELECT
 *
FROM
 USER
WHERE
 birth_date >= DATE_FORMAT('2019-10-10', '%Y-%m-%d');

EXPLAIN
SELECT
 *
FROM
 USER
WHERE
 birth_date >= DATE_FORMAT('2019-10-10', '%Y-%m-%d')
AND birth_date <= DATE_FORMAT('2020-12-10', '%Y-%m-%d');

Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

2番目の方法:

EXPLAIN
SELECT
 *
FROM
 USER
WHERE
 DATE_FORMAT(birth_date, '%Y-%m-%d') >= '2019-10-10';

EXPLAIN
SELECT
 *
FROM
 USER
WHERE
 DATE_FORMAT(birth_date, '%Y-%m-%d') >= '2019-10-10'
AND DATE_FORMAT(birth_date, '%Y-%m-%d') <= '2020-12-10';

Ali:条件フィールドにインデックスが付けられていますが、クエリが非常に遅いのはなぜですか?

上記の2セットのSQLは、フィールドとパラメーターにDATE_FORMATを追加することによってテストされました。結果は、図に示されています。birth_dateインデックスは、主にフィールドキーによっては効果的ではありません 

したがって、開発プロセスでは、このタイプの関数の使用を避ける必要があります。そうしないと、インデックスの障害やテーブル全体のスキャンが発生する可能性があります。

総括する

実際の状況に応じて選択してください:

①DATE_FORMATの最初のメソッドを使用し、クエリフィールドの代わりにクエリパラメータでDATE_FORMATを使用します

EXPLAIN
SELECT
 *
FROM
 USER
WHERE
 birth_date >= DATE_FORMAT('2019-10-10', '%Y-%m-%d')
AND birth_date <= DATE_FORMAT('2020-12-10', '%Y-%m-%d');

②DATE_FORMATの2番目の方法は使用しないでください。クエリ1などの範囲に従ってクエリを実行してください。

-- 举例:
EXPLAIN SELECT
 *
FROM
 USER
WHERE
 create_time >= '2026-10-24 00:00:00'
AND create_time <= '2026-10-24 23:59:59';

最後に書く

私の公開アカウント[風と波はコードと同じくらい静かです]に注目してください。Java関連の記事、学習資料が多数更新され、編集された資料もそこに配置されます。

文章が良いと思うなら、それと同じようにフォロワーを追加してください!注意して、迷子にならないで、更新を続けてください!

おすすめ

転載: blog.51cto.com/14957073/2562904