如何索引100万行mySQL表进行简单查询

时间:2013-11-12 04:47:32

标签: mysql optimization indexing

我有一个约1百万条的mySQL DB。

我运行查询:

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 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;
+----+-------------+-------+-------+---------------+-----------+---------+------+--------+----------+-------+
| id | select_type | table | type  | possible_keys | key       | key_len | ref  | rows   | filtered | Extra |
+----+-------------+-------+-------+---------------+-----------+---------+------+--------+----------+-------+
|  1 | SIMPLE      | a     | index | NULL          | published | 8       | NULL | 616200 |   152.94 |       |
+----+-------------+-------+-------+---------------+-----------+---------+------+--------+----------+-------+
1 row in set, 1 warning (0.46 sec)

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

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

您看到使用published密钥的原因是因为您正在订购该密钥。这个查询需要多久运行一次?

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

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

  1. 按DESC顺序排序前616200 行,然后
  2. 最后将结果限制为50行。
  3. 如果可能,您应该以不同的方式过滤数据库的结果。将结果更改为基于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”作为您唯一的分页方法。 LIMIT是惊人的,是的,但它没有针对您尝试执行此操作的方式检索记录进行优化,因为您需要按日期排序。

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