我目前是网站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;
以下是解释计划:
以下是关键:
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”有一个索引。
以下是我的问题:
为什么显示正在扫描382k行?不应该通过ID DESC LIMIT 40的订单总是将它限制到更少,即找到与WHERE匹配的40行然后停止?
当网站运行一年,并且说有12米行时,此查询是否仍会缩放? MySQL是否足够聪明,可以通过“ORDER BY Id DESC”实现从磁盘上数据集的末尾开始并向后工作?
我一直在考虑将此查询完全扁平化为更多视图样式表“SELECT l.* FROM validlinks v JOIN links l ON l.Id = v.LinkId ORDER BY Id DESC LIMIT 40
”。但这个简单的联合会值得吗?
任何意见都会受到赞赏。
VERSION():5.7.10-log
创建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
答案 0 :(得分:2)
如果你想要速度,你将不得不在这个查询中抛弃一堆垃圾。
不要将内容标记为已删除,请将其删除。如果需要存档,请将它们转储到辅助表中。只是让他们不在路上。
尽可能积极地清除无效数据。这样可以消除查询中的NOT NULL
等测试。您可以过滤在应用程序层中获得的任何杂散记录。
不要使用LIKE
,这会导致巨大的表扫描。而是使用全文索引。那些速度要快得多。
构建包含所有条件的索引。尝试并对其进行排序,使得第一项排除相对于后者的最多数据。
如果你必须按原样对其进行索引:
CREATE INDEX idx_links_for_searching (Deleted, Type, id)
添加全文,您就会做得更好。