给定用例的最佳 MySQL table 模式

Optimal MySQL table schema for given use case

我有两个 tables - booksimagesbooks 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,其中每个作者将有一个 idname,就像一本书。

为了获得最佳性能,您需要 suitable 覆盖索引可用。例如:

... on `books` (`name`,`id`,`releasedate`)
... on `images` (`bookid`,`poster`,`bucketname`)

我们希望 name 作为索引中的前导列,因为 WHERE 子句中的相等谓词。我们希望 id 和 releaseate 也包含在索引中,使其成为 "covering index",因此可以从索引中满足查询,而不需要访问底层 table 的页面来检索值。

由于 ON 子句中的引用,我们希望 bookid 作为前导列。同样,在索引中提供 posterbucketname 使其成为 "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 = ?