给定用例的最佳 MySQL table 模式
Optimal MySQL table schema for given use case
我有两个 tables - books
和 images
。 books
table 有很多列 - 包括 id
(主键)、name
(不唯一)、releasedate
等。images
table 有两列 - id
(这不是唯一的,即一个书 ID 可能有多个与之关联的图像,我们需要所有这些图像。此列具有非唯一索引) , 和 poster
(这是唯一的主键,所有图像都在同一个桶中,因此不能有重复的名称)。我的要求是给定一个书名,找到与之相关的所有图像(连同发行年份和每张图像的 bucketname
,在这种情况下 bucketname
只是一个数字)。
我是运行这个查询:
select books.id,poster,bucketname,year(releasedate) from books
inner join images where images.bookId = books.id and books.name = "<name>";
示例结果集可能如下所示:
如您所见,有两个结果匹配 - 一个匹配 id
2 和 year
1989,有 5 张图像,另一个匹配 id
261009,year
2013 和一张图片。
问题是,查询速度极慢。在零负载下,MySQL 控制台本身需要大约 0.14 秒(在生产中可能有多个并发请求,它们可能会排队,导致进一步延迟),这是自动完成的 unacceptable。谁能告诉我如何通过向 table 添加正确的 indices/keys 来优化查询?如果 MySQL 不可能,关于正确的 Redis 模式的建议也会很有用。
编辑:大约没有。 images
- 480k 中的行数,books
- 285k 中的行数。将来,自动完成将显示书籍作者和书名的结果,因此查询将需要扩展以考虑单独的 table authors
,其中每个作者将有一个 id
和 name
,就像一本书。
为了获得最佳性能,您需要 suitable 覆盖索引可用。例如:
... on `books` (`name`,`id`,`releasedate`)
... on `images` (`bookid`,`poster`,`bucketname`)
我们希望 name
作为索引中的前导列,因为 WHERE 子句中的相等谓词。我们希望 id 和 releaseate 也包含在索引中,使其成为 "covering index",因此可以从索引中满足查询,而不需要访问底层 table 的页面来检索值。
由于 ON 子句中的引用,我们希望 bookid
作为前导列。同样,在索引中提供 poster
和 bucketname
使其成为 "covering" 索引。
使用EXPLAIN
查看查询执行计划。
此外,请注意,如果未在 images
中找到匹配行,则内部联接操作不会 return 来自 books
的行。如果我们想要 return 来自 books
的一行,即使没有图像可用,我们也可以使用外部连接。
我会这样写查询:
SELECT b.id
, i.poster
, i.bucketname
, YEAR(b.releasedate)
FROM books b
LEFT
JOIN images i
ON i.bookid = b.id
WHERE b.name = ?
我有两个 tables - books
和 images
。 books
table 有很多列 - 包括 id
(主键)、name
(不唯一)、releasedate
等。images
table 有两列 - id
(这不是唯一的,即一个书 ID 可能有多个与之关联的图像,我们需要所有这些图像。此列具有非唯一索引) , 和 poster
(这是唯一的主键,所有图像都在同一个桶中,因此不能有重复的名称)。我的要求是给定一个书名,找到与之相关的所有图像(连同发行年份和每张图像的 bucketname
,在这种情况下 bucketname
只是一个数字)。
我是运行这个查询:
select books.id,poster,bucketname,year(releasedate) from books
inner join images where images.bookId = books.id and books.name = "<name>";
示例结果集可能如下所示:
如您所见,有两个结果匹配 - 一个匹配 id
2 和 year
1989,有 5 张图像,另一个匹配 id
261009,year
2013 和一张图片。
问题是,查询速度极慢。在零负载下,MySQL 控制台本身需要大约 0.14 秒(在生产中可能有多个并发请求,它们可能会排队,导致进一步延迟),这是自动完成的 unacceptable。谁能告诉我如何通过向 table 添加正确的 indices/keys 来优化查询?如果 MySQL 不可能,关于正确的 Redis 模式的建议也会很有用。
编辑:大约没有。 images
- 480k 中的行数,books
- 285k 中的行数。将来,自动完成将显示书籍作者和书名的结果,因此查询将需要扩展以考虑单独的 table authors
,其中每个作者将有一个 id
和 name
,就像一本书。
为了获得最佳性能,您需要 suitable 覆盖索引可用。例如:
... on `books` (`name`,`id`,`releasedate`)
... on `images` (`bookid`,`poster`,`bucketname`)
我们希望 name
作为索引中的前导列,因为 WHERE 子句中的相等谓词。我们希望 id 和 releaseate 也包含在索引中,使其成为 "covering index",因此可以从索引中满足查询,而不需要访问底层 table 的页面来检索值。
由于 ON 子句中的引用,我们希望 bookid
作为前导列。同样,在索引中提供 poster
和 bucketname
使其成为 "covering" 索引。
使用EXPLAIN
查看查询执行计划。
此外,请注意,如果未在 images
中找到匹配行,则内部联接操作不会 return 来自 books
的行。如果我们想要 return 来自 books
的一行,即使没有图像可用,我们也可以使用外部连接。
我会这样写查询:
SELECT b.id
, i.poster
, i.bucketname
, YEAR(b.releasedate)
FROM books b
LEFT
JOIN images i
ON i.bookid = b.id
WHERE b.name = ?