嵌套索引的 MySQL 性能

标签 mysql performance indexing

我有一个带有嵌套索引(blog_id,已发布)的 mysql 表(文章),并且性能很差。我在慢查询日志中看到很多这样的内容:

- 查询时间:23.184007 锁定时间:0.000063 已发送行数:380 已检查行数:6341 从文章中选择 id WHERE Category_id = 11 AND blog_id IN (13,14,15,16,17,18,19,20,21,22,23,24,26,27,6330,6331,8269,12218,18889)按发布的 DESC LIMIT 380 排序;

我无法理解为什么 mysql 会运行带有这些 blog_ids 的所有行来找出我的前 380 行。我希望嵌套索引的全部目的是加快速度。至少,即使是一个简单的实现,也应该按 blog_id 查找并获取按已发布排序的前 380 行。这应该很快,因为由于嵌套索引,我们可以计算出确切的 200 行。然后对得到的 19*200=3800 行进行排序。

如果要以最优化的方式实现它,您可以从所有基于 blog-id 的流集中放入一个堆,然后选择具有 max(published) 的流并重复 200 次。每个操作都应该很快。

自从 Google、Facebook、Twitter、Microsoft 和所有大公司都将 mysql 用于生产目的以来,我肯定错过了一些东西。有哪位有经验的吗?

编辑:根据 thieger 的回答进行更新。我尝试过索引提示,但似乎没有帮助。结果附在下面的最后。 Mysql order by optimisation声称要解决 theiger 提出的问题:

I agree that MySQL might possibly use the composite blog_id-published-index, but only for the blog_id part of the query.

SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2;

至少 mysql 似乎声称它的用途不仅仅限于 WHERE 子句(查询的 blog_id 部分)。有帮助吗?

谢谢, -普拉桑那 [myprasanna at gmail dot com]

CREATE TABLE IF NOT EXISTS `articles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `category_id` int(11) DEFAULT NULL,
  `blog_id` int(11) DEFAULT NULL,
  `cluster_id` int(11) DEFAULT NULL,
  `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `description` text COLLATE utf8_unicode_ci,
  `keywords` text COLLATE utf8_unicode_ci,
  `image_url` varchar(511) COLLATE utf8_unicode_ci DEFAULT NULL,
  `url` varchar(511) COLLATE utf8_unicode_ci DEFAULT NULL,
  `url_hash` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `author` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `categories` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `published` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  `is_image_crawled` tinyint(1) DEFAULT NULL,
  `image_candidates` text COLLATE utf8_unicode_ci,
  `title_hash` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `article_readability_crawled` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `index_articles_on_url_hash` (`url_hash`),
  KEY `index_articles_on_cluster_id` (`cluster_id`),
  KEY `index_articles_on_published` (`published`),
  KEY `index_articles_on_is_image_crawled` (`is_image_crawled`),
  KEY `index_articles_on_category_id` (`category_id`),
  KEY `index_articles_on_title_hash` (`title_hash`),
  KEY `index_articles_on_article_readability_crawled` (`article_readability_crawled`),
  KEY `index_articles_on_blog_id` (`blog_id`,`published`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=562907 ;

SELECT id from articles USE INDEX(index_articles_on_blog_id) WHERE category_id = 11 AND blog_id IN (13,14,15,16,17,18,19,20,21,22,23,24,26,27,6330,6331,8269,12218,18889) order by published DESC LIMIT 380;

....
380 rows in set (11.27 sec)

explain SELECT id from articles USE INDEX(index_articles_on_blog_id) WHERE category_id = 11 AND blog_id IN (13,14,15,16,17,18,19,20,21,22,23,24,26,27,6330,6331,8269,12218,18889) order by published DESC LIMIT 380\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: articles
         type: range
possible_keys: index_articles_on_blog_id
          key: index_articles_on_blog_id
      key_len: 5
          ref: NULL
         rows: 8640
        Extra: Using where; Using filesort
1 row in set (0.00 sec)

最佳答案

您是否尝试过 EXPLAIN 来查看您的索引是否已被使用?您是否已分析更新索引统计信息?

我同意 MySQL 可能会使用复合 blog_id-published-index,但仅限于查询的 blog_id 部分。如果在 ANALYZE 之后没有使用索引,你可以尝试用 USE INDEX 甚至 FORCE INDEX 给 MySQL 一个提示,但是 MySQL 优化器也可能正确地认为顺序扫描比使用索引更快。对于您的查询类型,我还建议在category_id和blog_id上添加索引并尝试使用它。

关于嵌套索引的 MySQL 性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3401236/

相关文章:

php - 我期待不同的 sql 结果

python - 如何通过 Pandas 数据框的列值加快行选择

indexing - Tkinter Optionmenu 小部件中相同值的索引

c# - 逐行浏览某些文本时令人困惑的索引错误

mysql - 根据另一个字段更新mysql部分

MySQL If else 构造语法

r - 如何按组加速子集

string - AS3 - 使用字符索引删除字符串的一部分

mysql - 构建关注者/关注 MySQL 数据库的最佳实践

c++ - 为什么在排序算法的实现中 vector 明显慢于数组?