我在使用 MySQL (innoDB) 5.0 时遇到严重问题。
一个非常简单的 SQL 查询是用一个非常意外的查询计划执行的。
查询:
SELECT
SQL_NO_CACHE
mbCategory.*
FROM
MBCategory mbCategory
INNER JOIN ResourcePermission as rp
ON rp.primKey = mbCategory.categoryId
where mbCategory.groupId = 12345 AND mbCategory.parentCategoryId = 0
limit 20;
MBCategory - 包含 216583 行
ResourcePermission - 包含 3098354 行。
在 MBCategory 中,我有多个索引(列顺序与索引中相同):
Primary (categoryId)
A (groupId,parentCategoryId,categoryId)
B (groupId,parentCategoryId)
在 ResourcePermission 中,我有多个索引(列顺序与索引中相同):
Primary - on some column
A (primKey).
当我查看查询计划时,Mysql 更改表顺序并首先从 ResourcePermission 中选择行,然后它加入 MBCategory 表(疯狂的想法),这需要很长时间。所以我添加了
STRAIGHT_JOIN
来强制innodb引擎使用正确的表顺序:
SELECT
STRAIGHT_JOIN SQL_NO_CACHE
mbCategory.*
FROM
MBCategory
mbCategory
INNER JOIN ResourcePermission as rp
ON rp.primKey = mbCategory.categoryId
where mbCategory.groupId = 12345 AND mbCategory.parentCategoryId = 0
limit 20;
但是这里有第二个问题: 在我看来,mysql应该在连接操作上使用
index A (primKey)
,而不是对每条记录执行范围检查(索引映射:0x400),这又需要很长时间!
强制索引没有帮助,mysql仍然对每条记录执行范围检查。
MBCategory 中只有 23 行满足 where 条件,连接后只有 75 行。 我怎样才能让mysql在此操作上选择正确的索引?
好的, 基本问题。 我欠自己一杯啤酒。 我最近调整的系统不是我开发的系统 - 我的管理层指派我使用它来提高性能(原始团队对此主题不了解)。
经过数周的改进 SQL 查询、索引、应用程序正在执行的 SQL 查询数量后,我没有检查本例中最重要的事情之一!!
柱类型不同!
编写过此类代码的开发人员应该得到很大的讨论。
感谢您的帮助!
我遇到了同样的问题,但原因不同。我正在加入一个大表,ON 子句使用 OR 将主键 (ii.itemid) 与两个不同的列进行比较:
SELECT *
FROM share_detail sd
JOIN box_view bv ON sd.container_id = bv.id
JOIN boxes b ON b.id = bv.shared_id
JOIN item_index ii ON ii.itemid = bv.shared_id OR b.parent_itemid = ii.itemid;
幸运的是,事实证明parent_itemid比较是多余的,所以我能够删除它。现在该索引正在按预期使用。否则,我将尝试将 item_index 连接拆分为两个单独的连接。
对 @Wojtek Rudziński 的绝对正确答案的一点补充:
就我而言,原因是 varchar 列的字符集/排序规则不同。也检查一下。