2014-11-03 106 views
2

我有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。是的,我已经考虑了减少查询中表的数量的方法;我需要获取的信息需要每个我正在访问的表,并且我无法更改数据库的体系结构。

最后,我可以在这里改变的唯一的东西是查询和索引/约束。由于这是一个先前存在的系统,因此我一直坚持一切。 我还有其他方法可以更好地优化此操作吗?

谢谢!

编辑:我定为超级查询的格式。

回答

0

你可以添加一个索引,这个模式?

如果是的话,我建议你复合索引(name, pKey)添加到您的表A。不要费心去设置一个独特的约束;你已经用你的其他索引处理过了。该化合物将允许您的选择标准A.name=parameter_1和您的联接满足一个索引扫描。

您使用单列表C只是简单地删除不在该表中的结果集行。除非您的查询有可怕的性能问题,否则我不担心它从EXPLAIN中丢失。

通常,在处理这些多路连接操作时,应该尝试使用复合覆盖索引来帮助您的性能。你可以阅读这种索引。

+0

我添加了你建议的索引,并没有区别。表C实际上具有更多列,即一个主键,并且我从这些列中选择值。由于我不认为这些附加列与JOIN操作有关,所以我没有包含它们。 – wizard07KSU 2014-11-04 00:32:08