大規模なデータベースで実行される次のクエリがあります。
select TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime))
from users
where categoryType='1'
and TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) < 1000
TIME_TO_SECがクエリとwhere句で使用されていることに気付いた場合。
私はエイリアスを試しましたが、エイリアスは使用できないため、より良い解決策が何であるかわかりません。
私はあなたの問題を照会するための唯一の最適化された方法を見つけます。WHERE句のフィールドから値を計算する場合、MySQLは各行を計算する必要があります。したがって、それは全表スキャンのたびであり、多くの時間を使用する可能性があり、パフォーマンスはあまり高くありません。
計算されたtimediffとインデックスを使用して新しいフィールドを使用します。計算する必要はありません。フィールドを挿入または変更すると自動的に計算されるVIRTUALPERSISTENTフィールドを使用できます。
私は自分の考えを明確にするために同じサンプルを作成しました:
まず、新しいテーブルを作成します。
CREATE TABLE `users` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`walkStartTime` TIMESTAMP NULL DEFAULT NULL,
`walkEndTime` TIMESTAMP NULL DEFAULT NULL,
`categoryType` INT(11) DEFAULT NULL,
`diffp` INT(11) AS (TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime))) PERSISTENT,
PRIMARY KEY (`id`),
KEY `diffs` (`diffp`)
) ENGINE=INNODB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
いくつかのものを挿入します:
INSERT INTO `users` (`id`, `walkStartTime`, `walkEndTime`, `categoryType`)
VALUES
(1, '2015-09-27 07:00:00', '2015-09-27 07:30:00', 1),
(2, '2015-09-27 07:00:01', '2015-09-27 07:31:00', 1),
(3, '2015-09-27 07:00:02', '2015-09-27 07:32:00', 0),
(4, '2015-09-27 07:00:10', '2015-09-27 07:15:00', 1),
(5, '2015-09-27 07:00:20', '2015-09-27 07:16:10', 1),
(6, '2015-09-27 07:00:30', '2015-09-27 07:17:20', 0),
(7, '2015-09-27 07:01:00', '2015-09-27 07:10:00', 1),
(8, '2015-09-27 07:02:00', '2015-09-27 07:09:33', 1),
(9, '2015-09-27 07:03:00', '2015-09-27 08:12:00', 1);
クエリを試して説明してください:9行すべてを読み取っていることを確認してください
MariaDB [tmp]> select TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime))
-> from users
-> where categoryType='1'
-> and TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime)) < 1000;
+--------------------------------------------------+
| TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime)) |
+--------------------------------------------------+
| 890 |
| 950 |
| 540 |
| 453 |
+--------------------------------------------------+
4 rows in set (0.00 sec)
MariaDB [tmp]> EXPLAIN select TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime))
-> from users
-> where categoryType='1'
-> and TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime)) < 1000;
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 9 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
MariaDB [tmp]>
新しいVIRTUALフィールド(diffp)を使用して最適化されたクエリを実行します。
MariaDB [tmp]> SELECT diffp
-> FROM users
-> WHERE diffp < 1000;
+-------+
| diffp |
+-------+
| 453 |
| 540 |
| 890 |
| 950 |
+-------+
4 rows in set (0.00 sec)
MariaDB [tmp]> EXPLAIN SELECT diffp
-> FROM users
-> WHERE diffp < 1000;
+------+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | users | range | diffs | diffs | 5 | NULL | 3 | Using where; Using index |
+------+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
MariaDB [tmp]>
したがって、MySQLが3つのROWSのみを読み取り、インデックスを使用していることがわかります。両方のフィールド(diffpとCategoryType)で複合インデックスを使用すると、速度が向上する可能性もあります。また、インデックス内の両方のフィールドの順序によって速度が変わる可能性があります。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加