繁体   English   中英

如何优化对MySQL派生列执行ORDER BY的查询?

[英]How can I optimize a query that does an ORDER BY on a derived column in MySQL?

我在优化涉及GROUP BY,ORDER BY和LIMIT的相对简单的查询时遇到了麻烦。 该表有30万条记录。 这是模式(我添加了一些额外的索引进行试验):

CREATE TABLE `scrape_search_results` (
  `id` int(11) NOT NULL auto_increment,
  `creative_id` int(11) NOT NULL,
  `url_id` int(11) NOT NULL,
  `access_date` datetime NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `creative_url_index` (`creative_id`,`url_id`),
  KEY `access_date_index` (`access_date`),
  KEY `access_date_creative_id_index` (`access_date`,`creative_id`),
  KEY `creative_id_access_date_index` (`creative_id`,`access_date`),
  KEY `test_index` USING HASH (`creative_id`)
) ENGINE=MyISAM AUTO_INCREMENT=4252725 DEFAULT CHARSET=latin1

在表格中,单个creative_id可能会出现多次(数百次)。 我要回答的查询是一个相对简单的查询。 给我由access_date排序的前20个creative_ids 这是我的SQL:

SELECT `ScrapeSearchResult`.`creative_id`, 
        MAX(`ScrapeSearchResult`.`access_date`) AS `latest_access_date` 
FROM `scrape_search_results` AS `ScrapeSearchResult` 
WHERE 1 = 1 
GROUP BY `ScrapeSearchResult`.`creative_id` 
ORDER BY `latest_access_date` DESC 
LIMIT 20;

这是执行此查询的结果,我们在这里看到第20个最大的access_date是2010-08-23 11:03:25:

+-------------+---------------------+
| creative_id | latest_access_date  |
+-------------+---------------------+
|         550 | 2010-08-23 11:07:49 | 
|        4568 | 2010-08-23 11:07:49 | 
|         552 | 2010-08-23 11:07:49 | 
|        2109 | 2010-08-23 11:07:49 | 
|        5221 | 2010-08-23 11:07:49 | 
|        1544 | 2010-08-23 11:07:49 | 
|        1697 | 2010-08-23 11:07:49 | 
|         554 | 2010-08-23 11:07:12 | 
|         932 | 2010-08-23 11:05:48 | 
|       11029 | 2010-08-23 11:05:37 | 
|       11854 | 2010-08-23 11:05:27 | 
|       11856 | 2010-08-23 11:05:05 | 
|         702 | 2010-08-23 11:03:56 | 
|        4319 | 2010-08-23 11:03:56 | 
|        7159 | 2010-08-23 11:03:56 | 
|       10610 | 2010-08-23 11:03:46 | 
|        5540 | 2010-08-23 11:03:46 | 
|           1 | 2010-08-23 11:03:46 | 
|       11942 | 2010-08-23 11:03:35 | 
|        7900 | 2010-08-23 11:03:25 | 
+-------------+---------------------+

如果要手动编写此算法,则将构建一个按顺序排列的b树( access_datecreative_id )。 我将从MAX(access_date) ,一直走到树,直到找到20个唯一的creative_ids ,然后按照找到它们的顺序返回。

使用该算法,我只需要考虑94行(有94行的access_date >= 2010-08-23 11:03:25 ,这是我们第20个最大的access_date如上所示)。

但是,MySQL决定在回答此查询时使用creative_url_index ,我不理解。 这样做时,它考虑超过10,000行。

ANALYZE TABLE scrape_search_results;
SELECT ...;
+----+-------------+--------------------+-------+---------------+--------------------+---------+------+-------+---------------------------------+
| id | select_type | table              | type  | possible_keys | key                | key_len | ref  | rows  | Extra                           |
+----+-------------+--------------------+-------+---------------+--------------------+---------+------+-------+---------------------------------+
|  1 | SIMPLE      | ScrapeSearchResult | index | NULL          | creative_url_index | 8       | NULL | 10687 | Using temporary; Using filesort | 
+----+-------------+--------------------+-------+---------------+--------------------+---------+------+-------+---------------------------------+

我在派生列MAX(access_date)上执行ORDER BY是我的麻烦吗? 如果是这样,我如何优化查询以使其更符合我的期望?

我已经有一段时间没有在MySQL中做过这种事情了(很久以来一直切换到PostgtreSQL),但是通常我会使用同心选择来处理这个问题,以欺骗查询计划者提供一个好的计划。

SELECT * FROM 
(SELECT `ScrapeSearchResult`.`creative_id`, 
        MAX(`ScrapeSearchResult`.`access_date`) AS `latest_access_date` 
FROM `scrape_search_results` AS `ScrapeSearchResult` 
WHERE 1 = 1 
GROUP BY `ScrapeSearchResult`.`creative_id` 

) as inner
ORDER BY `latest_access_date` DESC 
LIMIT 20;

不过,此操作的成功将完全取决于内部合理的总行数。

我只是查看了MySQL 5.6的文档, 看来应该工作……甚至在MySQL中也是如此;)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM