【问题标题】:How to index 1 million rows mySQL table for simple query如何为 100 万行 mySQL 表建立索引以进行简单查询
【发布时间】:2013-11-12 04:47:32
【问题描述】:

我有一个约 100 万个条目的 mySQL 数据库。

我运行查询:

SELECT a.id as aid, a.title as atitle, a.slug, summary, 
       a.link as alink, author, published, image, a.cat as acat, 
       a.rss as arss, a.site as asite 
  FROM articles a 
 ORDER BY published DESC 
 LIMIT 616150, 50;

加载大约需要 5 分钟或更长时间。

我的表和索引:

CREATE TABLE IF NOT EXISTS `articles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `slug` varchar(255) NOT NULL,
  `summary` text NOT NULL,
  `link` text NOT NULL,
  `author` varchar(255) NOT NULL,
  `published` datetime NOT NULL,
  `image` text NOT NULL,
  `cat` int(11) NOT NULL,
  `rss` int(11) NOT NULL,
  `site` int(11) NOT NULL,
  `bitly` varchar(255) NOT NULL,
  `checked` tinyint(4) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `title` (`title`),
  KEY `cat` (`cat`),
  KEY `published` (`published`),
  KEY `site` (`site`),
  KEY `rss` (`rss`),
  KEY `checked` (`checked`),
  KEY `id_publ_index` (`id`,`published`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1230234;

什么解释说:

mysql> EXPLAIN EXTENDED SELECT a.id asaid, a.title as atitle, a.slug, summary, a.link as alink, author, published, image, a.cat as acat, a.rss as arss, a.site作为来自文章的站点,已发布 DESC LIMIT 616150, 50 的订单; +----+-------------+--------+-------+-------------- -+-----------+---------+------+--------+---------- +-------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |过滤 |额外 | +----+-------------+--------+-------+-------------- -+-----------+---------+------+--------+---------- +-------+ | 1 |简单 |一个 |索引 |空 |发表 | 8 |空 | 616200 | 152.94 | | +----+-------------+--------+-------+-------------- -+-----------+---------+------+--------+---------- +-------+ 1 行,1 个警告(0.46 秒)

关于如何优化此查询的任何提示?为什么 mySQL 需要读取所有 616200 行,而不仅仅是被询问的 50 行?

感谢您的宝贵时间。

【问题讨论】:

标签: mysql optimization indexing


【解决方案1】:

您看到published 键被使用的原因是因为这是您订购的。此查询需要多久运行一次?

您可以做一件简单的事情来帮助这个查询运行得更快、更快: 更好地利用您的published 密钥。使用WHERE 定义您要从表中检索的日期范围。

您现在读取 616,200 行表的原因是因为您没有使用索引来限制范围。 MySQL 需要使用您的完整索引

  1. 按 DESC 顺序对 前 616200 行 行排序,然后
  2. 最终将结果限制为 50 行。

如果可能,您应该以不同的方式过滤数据库的结果。将结果更改为基于 WHERE(更有效地利用索引)将是最快的方法。

例如:

SELECT a.id as aid, a.title as atitle, a.slug, summary, 
       a.link as alink, author, published, image, a.cat as acat, 
       a.rss as arss, a.site as asite 
  FROM articles a 
 WHERE published > '2010-01-01'
 ORDER BY published DESC 
 LIMIT 6150, 50;

可悲的是 ORDER BY 和 LIMIT 不能很好地扩展,你会很快失去你的速度。 (例如,将您的限制更改为 0, 50,然后更改为 900000, 50 并查看您的速度如何受到影响),因此向您的 WHERE 添加更多信息将有助于您的查询更快。

编辑:

我无法知道按日期显示的内容,因此无法放置位置。此外,此查询在新闻聚合器上运行,它每……秒收集一次新闻。设置了限制,因此我可以创建分页结果。

因为您要插入新帖子,所以当用户浏览页面时,您的 LIMIT 语句将导致新闻项目跳转。例如,如果我在第一页,并且在我按“下一步”之前添加了三个项目,那么当我单击“下一步”时,我将看到上一页的最后三项

为了获得最佳用户体验,您应该尝试以某种方式将最后一次看到的新闻项目的 ID 或最后一次看到的新闻项目的日期添加到分页中。这可以通过会话或查询 URL 的一部分来完成,但它可以让您更好地使用索引。

我明白为什么会有限制 - 这只是在点击一定数量的页面后如何解决查询变慢的问题。

为了有效地解决您的速度问题,您需要更好地利用索引,而不是依赖“限制”作为您唯一的分页方法。 LIMIT 很棒,是的,但它并没有像您尝试那样检索记录进行优化,因为您需要按日期排序。

即使您说“我无法知道按日期显示什么”(至少目前...),您的应用程序必须有一种方法来限制需要从您的数据库中获取的内容。同样,Facebook 不需要浏览网站的每个成员的个人帖子,只是为了让结果显示在您的 Facebook 墙上。您需要了解如何提高效率。

【讨论】:

  • 我无法知道按日期显示什么,因此无法放置位置。此外,此查询在新闻聚合器上运行,它每……秒收集一次新闻。设置了限制,以便我可以创建分页结果。
  • 我在回答中添加了一些额外的解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
  • 2013-10-26
  • 2017-09-28
  • 1970-01-01
  • 2015-09-15
  • 2011-04-20
  • 1970-01-01
相关资源
最近更新 更多