15

我在使用 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;

但是这里的第二个问题materialzie:在我看来,mysql应该index A (primKey)在连接操作上使用,而不是它对每条记录执行范围检查(索引映射:0x400),这又需要很长时间!强制索引没有帮助,mysql 仍在为每条记录执行 Range 检查。

MBCategory 中只有 23 行满足 where 条件,加入后只有 75 行。如何让 mysql 在此操作中选择正确的索引?

4

2 回答 2

46

好的,初级问题。我欠自己一杯啤酒。我最近调整的系统不是我开发的系统 - 我的管理层已分配给我以提高绩效(原始团队不了解此主题)。

经过数周的改进 SQL 查询、索引、应用程序正在执行的 sql 查询数量后,我没有检查这种情况下最重要的事情之一!

列类型不同!

编写过代码的开发人员应该得到相当多的讨论。

感谢帮助 !

于 2012-11-07T08:50:05.610 回答
1

我遇到了同样的问题,但原因不同。我正在加入一个大表,并且 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 连接拆分为两个单独的连接。

于 2019-12-30T15:45:20.117 回答