1

我有一个约 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 行?

感谢您的时间。

4

1 回答 1

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 墙上。您需要了解如何提高效率。

于 2013-11-19T05:13:47.000 回答