MySQL多索引条件变慢了?

时间:2017-08-13 04:10:16

标签: mysql sql query-performance

我有一个像这样定义的表:

article | CREATE TABLE `article` (
  `id` varchar(64) NOT NULL,
  `type` varchar(16) DEFAULT NULL,
  `title` varchar(1024) DEFAULT NULL,
  `source` varchar(64) DEFAULT NULL,
  `over` tinyint(1) DEFAULT NULL,
  `taken` tinyint(1) DEFAULT NULL,
  `released_at` varchar(32) DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_article_over` (`over`),
  KEY `idx_article_created_at` (`created_at`),
  KEY `idx_article_type` (`type`),
  KEY `idx_article_taken` (`taken`),
  KEY `idx_article_updated_at` (`updated_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

mysql> select count(1) from article;
+----------+
| count(1) |
+----------+
|   649773 |
+----------+
1 row in set (0.61 sec)

当我进行查询时:

SELECT * FROM `article` where taken=0  ORDER BY updated_at asc limit 10;

SELECT * FROM `article` where over=0  ORDER BY updated_at asc limit 10;

他们都非常快 然而,当我使用它时,它变得非常慢:

SELECT * FROM `article` where taken=0 and over=0  ORDER BY updated_at asc limit 10;

需要4.94秒 如果文章表增长到2000万行,则需要更长的时间 以下是2000万行的解释:

mysql> explain SELECT * FROM `article` where taken=0 and processed=0  ORDER BY updated_at asc limit 10;
+----+-------------+-----------+------------+-------------+---------------------------------------------+---------------------------------------------+---------+------+---------+----------+-------------------------------------------------------------------------------------------+
| id | select_type | table     | partitions | type        | possible_keys                               | key                                         | key_len | ref  | rows    | filtered | Extra                                                                                     |
+----+-------------+-----------+------------+-------------+---------------------------------------------+---------------------------------------------+---------+------+---------+----------+-------------------------------------------------------------------------------------------+
|  1 | SIMPLE      | article   | NULL       | index_merge | idx_article_processed,idx_article_taken     | idx_article_processed,idx_article_taken     | 2,2     | NULL | 6234059 |   100.00 | Using intersect(idx_article_processed,idx_article_taken); Using where; Using filesort |
+----+-------------+-----------+------------+-------------+---------------------------------------------+---------------------------------------------+---------+------+---------+----------+-------------------------------------------------------------------------------------------+


mysql> SELECT * FROM `judgement` where taken=0 and processed=0  ORDER BY updated_at asc limit 10;
+--------------------------------------+----------+-----------+---------------------------------------------------------------------------
| id                                   | type     | title     | source|     processed | released_at | created_at       | updated_at  | taken |
+--------------------------------------+----------+-----------+---------------------------------------------------------------------------
10 rows in set (9 min 15.97 sec)

采取了,两个都有索引,为什么我把它们放在一起,查询变得更糟?由于索引越多,它不应该更快吗?

3 个答案:

答案 0 :(得分:3)

我不知道问题的确切答案“如果文章表增长到2000万行,为什么它会变慢”。
您的查询正在执行两项操作:

  • index_merge - 使用intersect(idx_article_processed,idx_article_taken)
  • 使用filesort

我只是猜测表中的多达2000万行MySql可以在内存中执行这两个操作,但是超过这个限制,其中一个操作(或者两个)都不能适合内存缓冲区而且MySql必须使用磁盘上的文件,速度要慢得多。

您可以增加内存缓冲区来调用某些MySql参数,也可以创建专用于查询的索引:

对于此查询:

SELECT * FROM `article` where taken=0  ORDER BY updated_at asc limit 10;

创建此索引:

CREATE INDEX my_new_index ON article( taken, updated_at )

对于此查询:

SELECT * FROM `article` 
where taken=0 and over=0  
ORDER BY updated_at asc limit 10;

创建此索引:

CREATE INDEX my_new_index1 ON article( taken, over, updated_at )

借助这些新索引,将消除filesort和megre操作。

答案 1 :(得分:0)

导航索引所涉及的工作比表扫描更快。是/否如果偶数分裂,索引就可以毫无价值。

如果您只有少数匹配,请考虑为相关行构建另一个表并加入,在处理它们时将其删除。在其他dbs中,您需要构建一个条件索引。

答案 2 :(得分:0)

它变得很慢"因为>>> from googlefinance import getQuotes >>> from urllib.parse import quote >>> print(getQuotes(quote("NSE:M&MFIN"))) [{'ID': '11784956', 'StockSymbol': 'M&MFIN', 'Index': 'NSE', 'LastTradePrice': '416.55', 'LastTradeWithCurrency': '₹416.55', 'LastTradeTime': '3:30PM GMT+5:30', 'LastTradeDateTime': '2017-08-18T15:30:00Z', 'LastTradeDateTimeLong': 'Aug 18, 3:30PM GMT+5:30'}] 都没有那么多行。 taken=0 and over=0太小了。但是,要小心,该设置不应该大到导致交换。你有多少RAM?