gpt4 book ai didi

MySQL 在使用 INNER JOIN 时不响应简单查询。特别是 "Sending data"需要太多时间

转载 作者:IT老高 更新时间:2023-10-29 00:12:00 25 4
gpt4 key购买 nike

我有两张 table ; songs 有 48 959 281 行,popular_songs 有 5 721 117 行。

这是两个表的结构:

CREATE TABLE songs (
songId BIGINT(20) NOT NULL,
songName VARCHAR(1000) NOT NULL,
songDuration BIGINT(20) NOT NULL,
songPreview VARCHAR(1000) NOT NULL,
PRIMARY KEY (songId),
INDEX (songDuration)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8
DEFAULT COLLATE utf8_general_ci;

CREATE TABLE popular_songs (
storeFrontId BIGINT(20) NOT NULL,
genreId BIGINT(20) NOT NULL,
songId BIGINT(20) NOT NULL,
songRank INT(11) NOT NULL,
INDEX (storeFrontId),
INDEX (genreId),
INDEX (songId),
INDEX (songRank),
CONSTRAINT popular_song UNIQUE (storeFrontId, genreId, songId),
FOREIGN KEY (storeFrontId) REFERENCES storefront (storeFrontId),
FOREIGN KEY (genreId) REFERENCES genre (genreId),
FOREIGN KEY (songId) REFERENCES songs (songId)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8
DEFAULT COLLATE utf8_general_ci;

当我在下面运行这两个问题时,一切正常。

mysql> SELECT count(*) FROM songs;
+----------+
| count(*) |
+----------+
| 48959281 |
+----------+
1 row in set (9.10 sec)

mysql> SHOW PROFILE;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.000008 |
| Waiting for query cache lock | 0.000002 |
| checking query cache for query | 0.000019 |
| checking permissions | 0.000003 |
| Opening tables | 0.000011 |
| System lock | 0.000004 |
| Waiting for query cache lock | 0.000017 |
| init | 0.000006 |
| optimizing | 0.000003 |
| statistics | 0.000004 |
| preparing | 0.000004 |
| executing | 0.000003 |
| Sending data | 9.100444 |
| end | 0.000012 |
| query end | 0.000005 |
| closing tables | 0.000008 |
| freeing items | 0.000007 |
| Waiting for query cache lock | 0.000002 |
| freeing items | 0.000012 |
| Waiting for query cache lock | 0.000002 |
| freeing items | 0.000001 |
| storing result in query cache | 0.000002 |
| logging slow query | 0.000001 |
| cleaning up | 0.000003 |
+--------------------------------+----------+
24 rows in set (0.00 sec)

mysql> SELECT count(*) FROM popular_songs;
+----------+
| count(*) |
+----------+
| 5721117 |
+----------+
1 row in set (1.34 sec)

mysql> SHOW PROFILE;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.000012 |
| Waiting for query cache lock | 0.000004 |
| checking query cache for query | 0.000037 |
| checking permissions | 0.000006 |
| Opening tables | 0.000017 |
| System lock | 0.000007 |
| Waiting for query cache lock | 0.000031 |
| init | 0.000010 |
| optimizing | 0.000017 |
| statistics | 0.000004 |
| preparing | 0.000004 |
| executing | 0.000003 |
| Sending data | 1.343991 |
| end | 0.000010 |
| query end | 0.000005 |
| closing tables | 0.000007 |
| freeing items | 0.000007 |
| Waiting for query cache lock | 0.000002 |
| freeing items | 0.000011 |
| Waiting for query cache lock | 0.000001 |
| freeing items | 0.000001 |
| storing result in query cache | 0.000002 |
| logging slow query | 0.000001 |
| cleaning up | 0.000003 |
+--------------------------------+----------+
24 rows in set (0.00 sec)

当我运行以下这些查询时,MySQL 没有响应。我不明白这是什么原因。

SELECT COUNT(*)
FROM songs
INNER JOIN popular_songs ON popular_songs.songId = songs.songId

SELECT COUNT(*)
FROM songs
INNER JOIN popular_songs ON popular_songs.songId = songs.songId
WHERE songs.songDuration > 0

更新:

MySQL 响应了以上两个查询。但是 Sending data 需要 250-300 秒。如何对此进行优化。

EXPLAIN EXTENDED 报告:

mysql> EXPLAIN EXTENDED
-> SELECT COUNT(*)
-> FROM songs
-> INNER JOIN popular_songs ON popular_songs.songId = songs.songId;
+----+-------------+---------------+--------+---------------+----------+---------+-----------------------------+---------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+--------+---------------+----------+---------+-----------------------------+---------+----------+-------------+
| 1 | SIMPLE | popular_songs | index | songId | songRank | 4 | NULL | 6449163 | 100.00 | Using index |
| 1 | SIMPLE | songs | eq_ref | PRIMARY | PRIMARY | 8 | itunes.popular_songs.songId | 1 | 100.00 | Using index |
+----+-------------+---------------+--------+---------------+----------+---------+-----------------------------+---------+----------+-------------+
2 rows in set, 1 warning (0.01 sec)

mysql> EXPLAIN EXTENDED
-> SELECT COUNT(*)
-> FROM songs
-> INNER JOIN popular_songs ON popular_songs.songId = songs.songId
-> WHERE songs.songDuration > 0;
+----+-------------+---------------+--------+----------------------+----------+---------+-----------------------------+---------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+--------+----------------------+----------+---------+-----------------------------+---------+----------+-------------+
| 1 | SIMPLE | popular_songs | index | songId | songRank | 4 | NULL | 6449163 | 100.00 | Using index |
| 1 | SIMPLE | songs | eq_ref | PRIMARY,songDuration | PRIMARY | 8 | itunes.popular_songs.songId | 1 | 100.00 | Using where |
+----+-------------+---------------+--------+----------------------+----------+---------+-----------------------------+---------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

当使用 INDEX songId 连接两个表时:

mysql> SELECT COUNT(*) FROM songs INNER JOIN popular_songs USE INDEX FOR JOIN (songId) ON popular_songs.songId = songs.songId;
+----------+
| COUNT(*) |
+----------+
| 5721117 |
+----------+
1 row in set (25.35 sec)

mysql> SHOW PROFILE;
+--------------------------------+-----------+
| Status | Duration |
+--------------------------------+-----------+
| starting | 0.000011 |
| Waiting for query cache lock | 0.000004 |
| checking query cache for query | 0.000045 |
| checking permissions | 0.000004 |
| checking permissions | 0.000004 |
| Opening tables | 0.000023 |
| System lock | 0.000007 |
| Waiting for query cache lock | 0.000030 |
| init | 0.000021 |
| optimizing | 0.000011 |
| statistics | 0.000020 |
| preparing | 0.000012 |
| executing | 0.000005 |
| Sending data | 25.350160 |
| end | 0.000019 |
| query end | 0.000005 |
| closing tables | 0.000024 |
| freeing items | 0.000022 |
| Waiting for query cache lock | 0.000002 |
| freeing items | 0.000016 |
| Waiting for query cache lock | 0.000001 |
| freeing items | 0.000001 |
| storing result in query cache | 0.000002 |
| logging slow query | 0.000001 |
| logging slow query | 0.000005 |
| cleaning up | 0.000003 |
+--------------------------------+-----------+
26 rows in set (0.00 sec)

挺好看的。但是,发送数据仍然需要 25 秒。

解释上述查询的扩展:

mysql> EXPLAIN EXTENDED SELECT COUNT(*) FROM songs INNER JOIN popular_songs USE INDEX FOR JOIN (songId) ON popular_songs.songId = songs.songId;
+----+-------------+---------------+--------+---------------+---------+---------+-----------------------------+---------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+--------+---------------+---------+---------+-----------------------------+---------+----------+-------------+
| 1 | SIMPLE | popular_songs | index | songId | songId | 8 | NULL | 2684407 | 100.00 | Using index |
| 1 | SIMPLE | songs | eq_ref | PRIMARY | PRIMARY | 8 | itunes.popular_songs.songId | 1 | 100.00 | Using index |
+----+-------------+---------------+--------+---------------+---------+---------+-----------------------------+---------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

最佳答案

我的猜测是 songDuration 上的索引让优化器感到困惑。您可以尝试这样表述查询:

SELECT COUNT(*)
FROM songs s
WHERE EXISTS (SELECT 1
FROM popular_songs ps
WHERE ps.songId = s.songId
) AND
s.songDuration > 0;

songDuration 上的索引最好也包含 songId:songs(songDuration, songId)

关于MySQL 在使用 INNER JOIN 时不响应简单查询。特别是 "Sending data"需要太多时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35481265/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com