我有一个包含约 1 百万个条目的 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 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 行?
感谢您的宝贵时间。
最佳答案
您看到正在使用 published
键的原因是因为这是您订购的内容。此查询需要多久运行一次?
您可以做一件简单的事情来帮助这个查询运行得非常非常快:
更好地利用您的 published
key 。使用 WHERE
定义您要从表中检索的日期范围。
您现在读取表的 616,200 行的原因是您没有使用索引来限制范围。 MySQL 需要使用您的完整索引来:
- 按 DESC 顺序对前 616200 行进行排序,然后
- 最终将结果限制为 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 添加更多信息将有助于您的查询快得多。
编辑:
There is no way I can know what to display by date, so putting a where is not possible. In addition this query is run on a news aggregator, that collects news every ... second. The limit is made so I can create paginated results.
因为您要插入新帖子,所以您的 LIMIT 语句将导致用户在浏览页面时跳转新闻项。例如,如果我在第一页上,在我按“下一步”之前添加了三个项目,那么在我单击“下一步”时,我将看到上一页的最后三项。
为了获得最佳用户体验,您应该尝试以某种方式将最后看到的新闻项的 ID 或最后看到的新闻项的日期添加到分页中。这可以通过 session 或查询 URL 的一部分来完成,但它可以让您更好地使用索引。
我理解为什么会存在限制 - 这就是您如何解决在点击一定数量的页面后查询变慢的问题。
要有效解决速度问题,您需要更好地利用索引,而不是依赖“LIMIT”作为唯一的分页方法。是的,LIMIT 很棒,但它并未针对您尝试的检索记录方式进行优化,因为您需要按日期排序。
即使你说“我无法知道按日期显示什么”(至少目前......)你的应用程序必须有一种方法来限制需要从你的数据库中获取的内容。与 Facebook 一样,不需要浏览网站的每个成员的个人帖子,只是为了在您的 Facebook 墙上显示结果。您需要了解如何提高它的效率。
关于mysql - 如何索引 100 万行 mySQL 表以进行简单查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19921055/