MySql - Innodb - 腐败指数/外键

时间:2017-05-30 01:26:31

标签: mysql indexing innodb

我有一种奇怪的奇怪情况。我的一个夜间查询通常需要5分钟,花了大约12个小时。这是查询:

SELECT  Z.id,
        Z.seoAlias,
        GROUP_CONCAT(DISTINCT LOWER(A.include)) AS include,
        GROUP_CONCAT(DISTINCT LOWER(A.exclude)) AS exclude
FROM df_productsbystore         AS X
INNER JOIN df_product_variants  AS Y ON Y.id = X.id_variant
INNER JOIN df_products          AS Z ON Z.id = Y.id_product
INNER JOIN df_advertisers       AS A ON A.id = X.id_store
WHERE X.isActive > 0
AND Z.id > 60301433
GROUP BY Z.id
ORDER BY Z.id
LIMIT 45000;

我跑了一个EXPLAIN并得到以下内容:

+----+-------------+-------+--------+------------------------------------------------------------------------------------+-----------+---------+---------------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys                                                                      | key       | key_len | ref                 | rows | Extra                           |
+----+-------------+-------+--------+------------------------------------------------------------------------------------+-----------+---------+---------------------+------+---------------------------------+
|  1 | SIMPLE      | A     | ALL    | PRIMARY                                                                            | NULL      | NULL    | NULL                |  365 | Using temporary; Using filesort |
|  1 | SIMPLE      | X     | ref    | UNIQUE_variantAndStore,idx_isActive,idx_store                                      | idx_store | 4       | foenix.A.id         |  600 | Using where                     |
|  1 | SIMPLE      | Y     | eq_ref | PRIMARY,UNIQUE,idx_prod                                                            | PRIMARY   | 4       | foenix.X.id_variant |    1 | Using where                     |
|  1 | SIMPLE      | Z     | eq_ref | PRIMARY,UNIQUE_prods_seoAlias,idx_brand,idx_gender2,fk_df_products_id_category_idx | PRIMARY   | 4       | foenix.Y.id_product |    1 | NULL                            |
+----+-------------+-------+--------+------------------------------------------------------------------------------------+-----------+---------+---------------------+------+---------------------------------+

这与我的开发环境有所不同。 df_advertisers部分看起来很可疑,所以我删除并重新创建了X.id_store列上的索引,现在EXPLAIN看起来像这样,查询又快了:

+----+-------------+-------+--------+------------------------------------------------------------------------------------+------------------------+---------+-------------------+---------+-------------+
| id | select_type | table | type   | possible_keys                                                                      | key                    | key_len | ref               | rows    | Extra       |
+----+-------------+-------+--------+------------------------------------------------------------------------------------+------------------------+---------+-------------------+---------+-------------+
|  1 | SIMPLE      | Z     | range  | PRIMARY,UNIQUE_prods_seoAlias,idx_brand,idx_gender2,fk_df_products_id_category_idx | PRIMARY                | 4       | NULL              | 2090691 | Using where |
|  1 | SIMPLE      | Y     | ref    | PRIMARY,UNIQUE,idx_prod                                                            | UNIQUE                 | 4       | foenix.Z.id       |       1 | Using index |
|  1 | SIMPLE      | X     | ref    | UNIQUE_variantAndStore,idx_isActive,idx_id_store                                   | UNIQUE_variantAndStore | 4       | foenix.Y.id       |       1 | Using where |
|  1 | SIMPLE      | A     | eq_ref | PRIMARY                                                                            | PRIMARY                | 4       | foenix.X.id_store |       1 | NULL        |
+----+-------------+-------+--------+------------------------------------------------------------------------------------+------------------------+---------+-------------------+---------+-------------+

看起来索引神奇地消失了。任何人都可以解释这有可能吗?我的意思是定期运行mysqlcheck命令或类似命令来避免这种情况吗?我很难过!

谢谢

2 个答案:

答案 0 :(得分:1)

下次,只需执行ANALYZE TABLE df_productsbystore;它会非常快,可以解决问题。

ANALYZE重新计算优化程序所依赖的统计信息,在这种情况下,决定从哪个表开始。在极少数情况下,统计数据会过时,需要胫骨。

警告:我假设您在最新版本上使用InnoDB。如果您使用的是MyISAM,则需要更频繁地ANALYZE

你真的需要45K行吗?你会怎么处理这么多人?

加速查询(可能)的一种方法是在子查询中使用X和Z执行所有操作,然后 JOIN A来完成剩下的工作:

SELECT  XYZ.id, XYZ.seoAlias,
        GROUP_CONCAT(DISTINCT LOWER(A.include)) AS include,
        GROUP_CONCAT(DISTINCT LOWER(A.exclude)) AS exclude
    FROM  
    (
        SELECT  Z.id, Z.seoAlias, X.id_store
            FROM  df_productsbystore AS X
            INNER JOIN  df_product_variants AS Y  ON Y.id = X.id_variant
            INNER JOIN  df_products AS Z          ON Z.id = Y.id_product
            WHERE  X.isActive > 0
              AND  Z.id > 60301433
            GROUP BY  Z.id -- may not be necessary ??
            ORDER BY  Z.id
            LIMIT  45000 
    ) AS XYZ
    INNER JOIN  df_advertisers AS A  ON A.id = XYZ.id_store
    GROUP BY  ZYZ.id
    ORDER BY  XYZ.id;

有用的索引:

Y: INDEX(id_product, id)
X: INDEX(id_variant, isActive, id_store)

答案 1 :(得分:0)

为了解决问题,我尝试删除并重新创建索引+ FK。这并没有在第一次解决问题时,机器处于负载状态,但它在安静的机器上第二次工作。

感觉就像mysql是片状的。我真的不知道还能说什么。

感谢您的帮助