【发布时间】:2014-07-23 00:27:46
【问题描述】:
我正在尝试改进我的查询,以便它不会花费这么长时间。有什么我可以尝试的吗?
我正在使用 InnoDB。
我的桌子:
mysql> describe hunted_place_review_external_urls;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| worker_id | varchar(255) | YES | MUL | NULL | |
| queued_at | bigint(20) | YES | MUL | NULL | |
| external_url | varchar(255) | NO | | NULL | |
| place_id | varchar(63) | NO | MUL | NULL | |
| source_id | varchar(63) | NO | | NULL | |
| successful | tinyint(1) | NO | | 0 | |
+--------------+--------------+------+-----+---------+----------------+
mysql> show index from hunted_place_review_external_urls;
+-----------------------------------+------------+--------------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------------------------+------------+--------------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| hunted_place_review_external_urls | 0 | PRIMARY | 1 | id | A | 5118685 | NULL | NULL | | BTREE | | |
| hunted_place_review_external_urls | 1 | worker_id | 1 | worker_id | A | 5118685 | NULL | NULL | YES | BTREE | | |
| hunted_place_review_external_urls | 1 | queued_at | 1 | queued_at | A | 5118685 | NULL | NULL | YES | BTREE | | |
| hunted_place_review_external_urls | 1 | worker_id_and_queued_at | 1 | worker_id | A | 5118685 | NULL | NULL | YES | BTREE | | |
| hunted_place_review_external_urls | 1 | worker_id_and_queued_at | 2 | queued_at | A | 5118685 | NULL | NULL | YES | BTREE | | |
| hunted_place_review_external_urls | 1 | place_id_source_id_external_url_successful | 1 | place_id | A | 5118685 | NULL | NULL | | BTREE | | |
| hunted_place_review_external_urls | 1 | place_id_source_id_external_url_successful | 2 | source_id | A | 5118685 | NULL | NULL | | BTREE | | |
| hunted_place_review_external_urls | 1 | place_id_source_id_external_url_successful | 3 | external_url | A | 5118685 | NULL | NULL | | BTREE | | |
| hunted_place_review_external_urls | 1 | place_id_source_id_external_url_successful | 4 | successful | A | 5118685 | NULL | NULL | | BTREE | | |
+-----------------------------------+------------+--------------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
我的查询:
mysql> select count(*) from hunted_place_review_external_urls;
+----------+
| count(*) |
+----------+
| 4217356 |
+----------+
1 row in set (0.96 sec)
mysql> select count(*) from hunted_place_review_external_urls where worker_id is null;
+----------+
| count(*) |
+----------+
| 772626 |
+----------+
1 row in set (0.27 sec)
mysql> update hunted_place_review_external_urls set worker_id = "123" where worker_id is null order by queued_at asc limit 1;
Query OK, 1 row affected (4.80 sec)
Rows matched: 1 Changed: 1 Warnings: 0
为什么即使我在queued_at 和worker_id 上都有单索引和复合索引,更新查询仍需要 4 秒?当 worker_id = null 的行数少得多时,这种情况以前从未发生过。使用约 200k 行而不是 780k 行,只需几毫秒。
请注意,使用 SELECT 而不是 UPDATE 的等效查询非常快:
mysql> select * from hunted_place_review_external_urls where worker_id is null order by queued_at asc limit 1;
1 row in set (0.00 sec)
我的queued_at 值是以毫秒数表示的时间戳,例如1398210069531
我已经尝试在 worker_id 和 queued_at 上删除我的单个索引,但问题仍然存在:
mysql> drop index queued_at on hunted_place_review_external_urls;
Query OK, 0 rows affected (3.75 sec)
mysql> drop index worker_id on hunted_place_review_external_urls;
Query OK, 0 rows affected (3.75 sec)
mysql> show index from hunted_place_review_external_urls;
+-----------------------------------+------------+--------------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------------------------+------------+--------------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| hunted_place_review_external_urls | 0 | PRIMARY | 1 | id | A | 5118685 | NULL | NULL | | BTREE | | |
| hunted_place_review_external_urls | 1 | worker_id_and_queued_at | 1 | worker_id | A | 5118685 | NULL | NULL | YES | BTREE | | |
| hunted_place_review_external_urls | 1 | worker_id_and_queued_at | 2 | queued_at | A | 5118685 | NULL | NULL | YES | BTREE | | |
| hunted_place_review_external_urls | 1 | place_id_source_id_external_url_successful | 1 | place_id | A | 5118685 | NULL | NULL | | BTREE | | |
| hunted_place_review_external_urls | 1 | place_id_source_id_external_url_successful | 2 | source_id | A | 5118685 | NULL | NULL | | BTREE | | |
| hunted_place_review_external_urls | 1 | place_id_source_id_external_url_successful | 3 | external_url | A | 5118685 | NULL | NULL | | BTREE | | |
| hunted_place_review_external_urls | 1 | place_id_source_id_external_url_successful | 4 | successful | A | 5118685 | NULL | NULL | | BTREE | | |
+-----------------------------------+------------+--------------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
这是我的EXPLAIN SELECT 声明。我使用的是不支持EXPLAIN UPDATE的旧版MYSQL:
mysql> explain select * from hunted_place_review_external_urls where worker_id is null order by queued_at asc limit 1;
+----+-------------+-----------------------------------+------+-------------------------+-------------------------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------------------------+------+-------------------------+-------------------------+---------+-------+---------+-------------+
| 1 | SIMPLE | hunted_place_review_external_urls | ref | worker_id_and_queued_at | worker_id_and_queued_at | 768 | const | 1587282 | Using where |
+----+-------------+-----------------------------------+------+-------------------------+-------------------------+---------+-------+---------+-------------+
1 row in set (0.00 sec)
【问题讨论】:
-
您是否尝试过使用
EXPLAIN?这将告诉您查询正在(不)使用哪些索引。 -
我使用的是旧版本的 mysql,它不能进行解释更新,但我在解释选择语句上做了,看起来它使用了正确的索引。我已经更新了我的问题。
-
停止这样做。
select * -
如果将其拆分为两个查询:
SELECT @id := id FROM ... ORDER BY queued_at LIMIT后跟UPDATE ... WHERE id = @id,会发生什么? -
我正在写一个与@Kermit 评论相关的答案,但后来意识到问题出在 UPDATE 中,但说实话,当您计算表中的所有列时,您的计数可能会出现偏差
标签: mysql sql database optimization query-optimization