我有4台MySQL数据库(不止于此着呢,但只有这4个相关的问题),让我们称之为A,B,C和D.这里的架构:奇怪的MySQL连接行为
CREATE TABLE A
(
pKey INT NOT NULL AUTO_INCREMENT,
name NVARCHAR(50),
PRIMARY KEY(pKey),
UNIQUE INDEX(name)
);
CREATE TABLE C
(
pKey INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(pKey)
);
CREATE TABLE B
(
pKey INT NOT NULL AUTO_INCREMENT,
aKey INT NOT NULL,
cKey INT NOT NULL,
PRIMARY KEY(pKey),
UNIQUE INDEX UniqueKey (aKey, cKey),
FOREIGN KEY(aKey) REFERENCES A(pKey),
FOREIGN KEY(cKey) REFERENCES C(pKey)
);
CREATE TABLE D
(
pKey INT NOT NULL AUTO_INCREMENT,
cKey INT NOT NULL,
PRIMARY KEY(pKey),
INDEX(cKey),
FOREIGN KEY(cKey) REFERENCES C(pKey)
);
我运行下面的查询:
SELECT
--stuff...
FROM A
INNER JOIN B
ON A.pKey=B.aKey
INNER JOIN C
ON B.cKey=C.pKey
INNER JOIN D
ON D.cKey=C.pKey
WHERE
A.name=parameter_1;
麻烦的是,这是一台服务器上运行一个大型数据库,大多数表有100K +的记录,它的情况并不少见一张桌子打破1000万条记录。一张桌子有超过2亿条记录。
撇开与MySQL的任何问题和架构(我卡与两个),我越来越有当我使用这个查询说明上面的查询一些奇怪的行为。由于这种行为,我有几个问题。我会先显示奇怪的行为。
如果我只是在MySql中解释上面的查询,那么我会在EXPLAIN输出的参考列中得到参考。但是,我需要将此查询作为较大查询的子查询来运行。 EXPLAINning较大查询给了我这样的事情以上查询(这只是一个对应表在此查询的较大查询行):
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
| 1 | SIMPLE | A | const | PRIMARY,key1,key2 | key1 | 38 | | 1 | |
| 1 | SIMPLE | D | index | key3 | key3 | 12 | NULL | 73868 | Using index |
| 1 | SIMPLE | C | index | PRIMARY,key3 | PRIMARY | 8 | NULL | 1 | |
| 1 | SIMPLE | B | ref | key4,UniqueKey,key6 | key4 | 12 | const,DB.D.key3 | 1 | Using where; Using index |
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
MySQL是做两点索引扫描和一个REF键入连接。如果我使用索引提示,我可以略微改善这一点,但只是略有改善。我之前说过,这个查询是作为一个子查询运行的。下面是其他查询的格式:
SELECT
--stuff
FROM
(
--sub-query1
) a
INNER JOIN
(
--the query I have a question about
) b
ON a.c1=b.c2
优化完全忽略表C中有利于做加入的两个外键列,B.cKey = D.cKey的。 所以,这里的问题1)为什么优化器忽略这样的表C?
接下来,即使我使用索引提示,并且它忽略了表C,它仍然执行索引扫描以加入B和D,尽管有适当的索引。 为什么?
在上面的解释中,它表明在表D中有73,868行,在这个问题时实际上有73,568行。其中一个查询表(在这个问题中没有显示)有大约1亿行,所以优化这个是相当重要的。对于完整查询,行列的乘积约为2.37E42。是的,我已经考虑了减少查询中表的数量的方法;我需要获取的信息需要每个我正在访问的表,并且我无法更改数据库的体系结构。
最后,我可以在这里改变的唯一的东西是查询和索引/约束。由于这是一个先前存在的系统,因此我一直坚持一切。 我还有其他方法可以更好地优化此操作吗?
谢谢!
编辑:我定为超级查询的格式。
我添加了你建议的索引,并没有区别。表C实际上具有更多列,即一个主键,并且我从这些列中选择值。由于我不认为这些附加列与JOIN操作有关,所以我没有包含它们。 – wizard07KSU 2014-11-04 00:32:08