MySql简单查询性能-1m行

MySql简单查询性能-1m行,mysql,Mysql,我目前是网站的开发者(NSFW)。我是唯一的创建者,我开始担心一个简单的查询,它是网站的核心(我绝不是DBA) 为了快速总结,它正在收集Twitch.TV聊天中的URL。它在3周内抢走了约70万辆。该网站直观地显示了最新的Imgur和Youtube视频。我有一个“links”表,其中有一个“favorites”表,我在其中存储了用户喜欢的链接(Id、LinkId、UserId) 问题是: SELECT Id, URL, CapturedOn, Channel,

我目前是网站的开发者(NSFW)。我是唯一的创建者,我开始担心一个简单的查询,它是网站的核心(我绝不是DBA)

为了快速总结,它正在收集Twitch.TV聊天中的URL。它在3周内抢走了约70万辆。该网站直观地显示了最新的Imgur和Youtube视频。我有一个“links”表,其中有一个“favorites”表,我在其中存储了用户喜欢的链接(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`)
“Channel-LIKE”语句可以在仅为特定用户最喜爱的频道请求链接时更改。这就变成了:

Channel IN (SELECT CONCAT('#', ChannelName) FROM channelfavourites WHERE UserId = X) AND
“Favorites”表的Id、UserId、LinkId列上有一个索引

“UserId”列的“channelfavorites”上有一个索引

以下是我的问题:

  • 为什么显示382k行正在被扫描?order by ID DESC LIMIT 40不应该总是将其限制在更小的范围内吗,即找到40行匹配WHERE-then-stop

  • 当这些网站运行了一年,据说有1200万行,这个查询还会扩展吗?MySQL是否足够聪明,能够实现“orderbyIDdesc”从磁盘上数据集的末尾开始并向后工作

  • 我一直在考虑将此查询完全展平到一个更具视图样式的表“
    SELECT l.*FROM validlinks v JOIN links l ON l.Id=v.LinkId ORDER BY Id DESC LIMIT 40
    ”。但这种简单的连接值得吗

    如有任何意见,将不胜感激

    信息 版本():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
    

    如果你想提高速度,你必须在这个查询中抛弃一堆垃圾

    不要将内容标记为已删除,请删除它们。如果需要归档这些文件,请将它们转储到辅助表中。把他们弄到一边去

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

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

    建立一个包含所有条件的索引。尝试对其进行排序,以便第一个项目排除与后面项目相关的大部分数据

    如果必须按原样编制索引:

    CREATE INDEX idx_links_for_searching (Deleted, Type, id)
    

    加上全文,你会做得更好。

    就像数据库上的谋杀一样。考虑全文索引。谢谢,不考虑那些。如果我可以去掉“LIKE”而只是一个“Channel='Blah'”,那会更好吗?请发布以下输出:SELECT VERSION();显示来自链接的索引;显示创建表链接;-我几乎可以肯定,您必须创建一个复合索引。MySQL使用“正常”每个查询只有一个索引Xact匹配可以被索引,它们通常非常快
    不能,MySQL必须针对每个可能匹配的行进行测试。@MeshMan-sh…-您可以看到优化器不使用新索引-(,但不要告诉他们这样做。这不是一个好主意。我会做一点事情。我会向您发送一个查询(带有子查询)并更改数据类型以加快您的请求。您只能将此查询的输出发送给我,然后将其添加到您的查询中并执行:选择…….过程分析();哎哟,现在我很尴尬。我认为按列添加索引是正确的方法。谢谢Tadman。@MeshMan一点也不麻烦。这是一件你必须进行大量实验才能理解的事情,所以请坚持下去。对大规模加载的数据库进行基准测试非常有用。