MySql - Innodb - 损坏的索引/外键

MySql - Innodb - Corrupt Index / Foreign Key

我遇到了一个该死的奇怪情况。我的一个夜间查询(通常需要 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;

我 运行 解释并得到以下内容:

+----+-------------+-------+--------+------------------------------------------------------------------------------------+-----------+---------+---------------------+------+---------------------------------+
| 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 命令或类似的命令来避免这种事情吗?我难住了!

谢谢

下次直接做ANALYZE TABLE df_productsbystore;会很快,而且可能解决问题

ANALYZE 重新计算优化器依赖于决定的统计信息,在本例中,table 从哪个开始。在极少数情况下,统计数据会过时并且需要在小腿上踢一脚。

警告:我假设您在较新的版本上使用 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)

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

就是感觉mysql很不稳定。真不知道还能说什么

谢谢你的帮助