自 MySQL 5.6 版本以来,一个非常简单但很长的查询所需的时间比 5.4 版本慢了几个数量级。
数据库结构:三个表,一个包含元素,一个包含类别,以及一个连接这两者的 M:N 表。创建语句如下:
当我添加一个元素时,执行时间激增到60秒加上200秒的提取时间。执行计划也会改变如下:
数据库结构:三个表,一个包含元素,一个包含类别,以及一个连接这两者的 M:N 表。创建语句如下:
CREATE TABLE element (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=4257455 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE category (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE elements_categories (
id int(11) NOT NULL AUTO_INCREMENT,
element_id int(11) NOT NULL,
category_id int(11) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY element_id (element_id,category_id),
KEY elements_categories_element_id (element_id),
KEY elements_categories_category_id (category_id),
CONSTRAINT D7d489b06a407a0c1c70f108712c815e FOREIGN KEY (category_id) REFERENCES category (id),
CONSTRAINT co_element_id_57f4f2ec0db9441c_fk_element_id FOREIGN KEY (element_id) REFERENCES element (id)
) ENGINE=InnoDB AUTO_INCREMENT=88131737 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
查询语句:
SELECT elements_categories.element_id, category.id, category.name
FROM category
INNER JOIN elements_categories
ON category.id = elements_categories.category_id
WHERE elements_categories.element_id IN (1, 2, 3, ...)
因此,在这个查询中,元素表甚至没有起到作用,我已经从之前的一个查询中得到了大量的ID。(免责声明:我正在使用ORM,即使是内联第一个查询也没有使事情变得更快。)IN子句中的值的数量可能会变得非常大,在我的例子中是14240。这不是问题,只需要花费十分之一秒左右。这是执行计划:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+--------+---------------------------------------------------------------------------+------------+---------+---------------------------------+-------+--------------------------+
| 1 | SIMPLE | elements_categories | range | element_id,elements_categories_element_id,elements_categories.category_id | element_id | 4 | NULL | 42720 | Using where; Using index |
| 1 | SIMPLE | category | eq_ref | PRIMARY | PRIMARY | 4 | elements_categories.category_id | 1 | NULL |
当我添加一个元素时,执行时间激增到60秒加上200秒的提取时间。执行计划也会改变如下:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+------+---------------------------------------------------------------------------+---------------------------------+---------+-------------+------+-------------+
| 1 | SIMPLE | category | ALL | PRIMARY | NULL | NULL | NULL | 75 | NULL |
| 1 | SIMPLE | elements_categories | ref | element_id,elements_categories_element_id,elements_categories_category_id | elements_categories_category_id | 4 | category.id | 760 | Using where |
range和eq_ref查询变为ALL和ref,表的顺序改变了,虽然elements_categories.category_id是这两个表之间的外键,但并没有将它作为ref。我不明白为什么执行计划会改变。
有75个类别、4,300,000个元素和1,600,000个分配。
我猜测我在某个方面超过了一些大小限制,但无法确定是哪个。此外,我没有对MySQL 5.5安装进行任何更改,它一直使用旧的执行计划。
elements_categories.element_id IN (1, 2, 3, ...)
或者有其他的where/join条件。您确定它是category.element_id IN ...
吗? - Vatev