MySql简单查询性能 - 1m行

时间:2016-05-22 08:48:45

标签: mysql

我目前是网站Twitch Links(NSFW)背后的开发人员。我是唯一的创建者,我开始担心一个简单的查询,它是网站的骨干(我绝不是DBA)。

为了快速总结,它正在从Twitch.TV聊天中收集URL。它在3周内被抓获约70万。该网站直观地显示了最新的Imgur和Youtube视频。我有一个“链接”表,有一个“收藏夹”表,我存储了用户喜欢的链接(Id,LinkId,UserId)。

以下是查询:

SELECT
    Id,
    URL,
    CapturedOn,
    Channel,
    (SELECT COUNT(*) FROM favourites WHERE LinkId = links.Id) AS NumFavourites, # Is this bad per row?
    Type,
    Data,
    CapturedBy
FROM links
WHERE
    Channel LIKE "%%" AND       # Can sometimes be populated with a single value, e.g. "Channel like '%riotgames%'"
    Type IN ('Imgur', 'YouTube') AND    # Can sometimes be "Type LIKE '%Imgur%'" or "Type LIKE '%Facebook%'" - there are about 20 different types.
    Deleted = 0 AND             # Out of 500k rows, about 100 will be deleted.
    Id > 0 AND         # Will be set to a high ID after first view to only return latest rows.
    Data IS NOT NULL            # Exclude badly parsed links.
ORDER BY
    Id DESC LIMIT 40;

以下是解释计划:

Explain Plan

以下是关键:

  PRIMARY KEY (`ID`),
  KEY `idx_links_Channel` (`Channel`),
  KEY `idx_links_Type` (`Type`),
  KEY `idx_links_CapturedOn` (`CapturedOn`)

仅在请求特定用户收藏频道的链接时,“频道LIKE”语句可能会发生变化。这变为:

Channel IN (SELECT CONCAT('#', ChannelName) FROM channelfavourites WHERE UserId = X) AND

在其Id,UserId,LinkId列的“收藏夹”表上有一个索引。

列“UserId”的“channelfavourites”有一个索引。

以下是我的问题:

  1. 为什么显示正在扫描382k行?不应该通过ID DESC LIMIT 40的订单总是将它限制到更少,即找到与WHERE匹配的40行然后停止?

  2. 当网站运行一年,并且说有12米行时,此查询是否仍会缩放? MySQL是否足够聪明,可以通过“ORDER BY Id DESC”实现从磁盘上数据集的末尾开始并向后工作?

  3. 我一直在考虑将此查询完全扁平化为更多视图样式表“SELECT l.* FROM validlinks v JOIN links l ON l.Id = v.LinkId ORDER BY Id DESC LIMIT 40”。但这个简单的联合会值得吗?

    任何意见都会受到赞赏。

    信息

    VERSION():5.7.10-log

    索引:Indexes

    创建SQL:

    CREATE TABLE `links` (
       `ID` int(11) NOT NULL AUTO_INCREMENT,
       `Type` varchar(45) DEFAULT NULL,
       `URL` text,
       `CapturedOn` datetime DEFAULT NULL,
       `CapturedBy` text,
       `Channel` varchar(100) DEFAULT NULL,
       `Data` text,
       `Deleted` bit(1) DEFAULT b'0',
       `DonationId` varchar(100) DEFAULT NULL,
       PRIMARY KEY (`ID`),
       KEY `idx_links_Channel` (`Channel`),
       KEY `idx_links_Type` (`Type`),
       KEY `idx_links_CapturedOn` (`CapturedOn`)
     ) ENGINE=InnoDB AUTO_INCREMENT=756661 DEFAULT CHARSET=utf8
    

1 个答案:

答案 0 :(得分:2)

如果你想要速度,你将不得不在这个查询中抛弃一堆垃圾。

不要将内容标记为已删除,请将其删除。如果需要存档,请将它们转储到辅助表中。只是让他们不在路上。

尽可能积极地清除无效数据。这样可以消除查询中的NOT NULL等测试。您可以过滤在应用程序层中获得的任何杂散记录。

不要使用LIKE,这会导致巨大的表扫描。而是使用全文索引。那些速度要快得多。

构建包含所有条件的索引。尝试并对其进行排序,使得第一项排除相对于后者的最多数据。

如果你必须按原样对其进行索引:

CREATE INDEX idx_links_for_searching (Deleted, Type, id)

添加全文,您就会做得更好。