3

过去在生产服务器上运行良好的查询开始变得非常缓慢(在几个小时内)。

就是这个:

SELECT * FROM news_articles WHERE published = '1' AND news_category_id = '4' ORDER BY date_edited DESC LIMIT 1;

执行最多需要20-30 秒(表有 ~200.000 行)

这是的输出EXPLAIN

+----+-------------+---------------+-------------+----------------------------+----------------------------+---------+------+------+--------------------------------------------------------------------------+
| id | select_type | table         | type        | possible_keys              | key                        | key_len | ref  | rows | Extra                                                                    |
+----+-------------+---------------+-------------+----------------------------+----------------------------+---------+------+------+--------------------------------------------------------------------------+
|  1 | SIMPLE      | news_articles | index_merge | news_category_id,published | news_category_id,published | 5,5     | NULL | 8409 | Using intersect(news_category_id,published); Using where; Using filesort |
+----+-------------+---------------+-------------+----------------------------+----------------------------+---------+------+------+--------------------------------------------------------------------------+

玩弄它,我发现暗示一个特定的索引 ( date_edited) 使它更快:

SELECT * FROM news_articles USE INDEX (date_edited) WHERE published = '1' AND news_category_id = '4' ORDER BY date_edited DESC LIMIT 1;

这需要几毫秒来执行

EXPLAIN这个的输出是:

+----+-------------+---------------+-------+---------------+-------------+---------+------+------+-------------+
| id | select_type | table         | type  | possible_keys | key         | key_len | ref  | rows | Extra       |
+----+-------------+---------------+-------+---------------+-------------+---------+------+------+-------------+
|  1 | SIMPLE      | news_articles | index | NULL          | date_edited | 8       | NULL |    1 | Using where |
+----+-------------+---------------+-------+---------------+-------------+---------+------+------+-------------+

news_category_id,publisheddate_edited都被索引。

存储引擎是 InnoDB。

这是表结构:

CREATE TABLE `news_articles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` text NOT NULL,
  `subtitle` text NOT NULL,
  `summary` text NOT NULL,
  `keywords` varchar(500) DEFAULT NULL,
  `body` mediumtext NOT NULL,
  `source` varchar(255) DEFAULT NULL,
  `source_visible` int(11) DEFAULT NULL,
  `author_information` enum('none','name','signature') NOT NULL     DEFAULT 'name',
  `date_added` datetime NOT NULL,
  `date_edited` datetime NOT NULL,
  `views` int(11) DEFAULT '0',
  `news_category_id` int(11) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `c_forwarded` int(11) DEFAULT '0',
  `published` int(11) DEFAULT '0',
  `deleted` int(11) DEFAULT '0',
  `permalink` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `news_category_id` (`news_category_id`),
  KEY `published` (`published`),
  KEY `deleted` (`deleted`),
  KEY `date_edited` (`date_edited`),
  CONSTRAINT `news_articles_ibfk_3` FOREIGN KEY (`news_category_id`) REFERENCES `news_categories` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
  CONSTRAINT `news_articles_ibfk_4` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=192588 DEFAULT CHARSET=utf8

我可能会更改我的 Web 应用程序执行的所有查询以提示使用该索引。但这是一项相当大的工作。

是否有某种方法可以调整 MySQL,以便在不实际重写所有查询的情况下提高第一个查询的效率?

4

3 回答 3

3

只是一些提示..

1 - 在我看来,发布的字段和 news_category_id 是整数。如果是这样,请从您的查询中删除单引号。在性能方面,它可以产生巨大的影响;

2 - 另外,我想说您发布的字段没有很多不同的值(可能是 1 - 是和 0 - 否,或类似的东西)。如果我是对的,这根本不是一个好的索引字段。在这种情况下,解析仍然需要遍历所有记录才能找到它要查找的内容;在这种情况下,将 news_category_id 移动到 WHERE 子句中的第一个字段。

3 - “不要忘记最左边的索引”。此确认对您的 SELECT、JOINS、WHERE、ORDER BY 有效。即使表格上列的位置也很重要,请将索引的列放在顶部。只要您知道如何使用索引,它们就是您的朋友。

希望它能以某种方式帮助你..

SELECT * FROM news_articles WHERE published = '1' AND news_category_id = '4' ORDER BY date_edited DESC LIMIT 1;

于 2013-04-18T07:11:29.777 回答
0

原来的: SELECT * FROM news_articles WHERE published = 1 AND news_category_id = 4 ORDER BY date_edited DESC LIMIT 1;

由于您有LIMIT 1,因此您只选择最新的行。ORDER BY date_edited告诉 MySQL 进行排序,然后从顶部取出 1 行。这真的很慢,为什么USE INDEX会有所帮助。

尝试在WHERE 子句中匹配MAX(date_edited)。这应该让查询规划器自动使用它的索引。

选择 MAX(date_entered): SELECT * FROM news_articles WHERE published = 1 AND news_category_id = 4 AND date_edited = (select max(date_edited) from news_articles);

于 2014-03-08T14:39:53.853 回答
-1

请将您的查询更改为:

SELECT * FROM news_articles WHERE published = 1 AND news_category_id = 4 ORDER BY date_edited DESC LIMIT 1;

请注意,我已从查询中提供的“1”和“4”数据中删除引号

传递的数据类型和列结构的差异不允许mysql能够使用这2列上的索引。

于 2013-04-18T06:59:57.113 回答