【发布时间】:2011-03-11 08:33:42
【问题描述】:
我正在运行 be 查询
SELECT packages.id, packages.title, subcat.id, packages.weight
FROM packages ,provider, packagestosubcat,
packagestocity, subcat, usertosubcat,
usertocity, usertoprovider
WHERE packages.endDate >'2011-03-11 06:00:00' AND
usertosubcat.userid = 1 AND
usertocity.userid = 1 AND
packages.providerid = provider.id AND
packages.id = packagestosubcat.packageid AND
packages.id = packagestocity.packageid AND
packagestosubcat.subcatid = subcat.id AND
usertosubcat.subcatid = packagestosubcat.subcatid AND
usertocity.cityid = packagestocity.cityid AND
(
provider.providertype = 'reg' OR
(
usertoprovider.userid = 1 AND
provider.providertype != 'reg' AND
usertoprovider.providerid = provider.ID
)
)
GROUP BY packages.title
ORDER BY subcat.id, packages.weight DESC
当我运行解释时,除了对 usertoprovider 表的扫描(似乎没有使用表的键)之外,一切似乎都正常:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE usertocity ref user,city user 4 const 4 Using temporary; Using filesort
1 SIMPLE packagestocity ref city,packageid city 4 usertocity.cityid 419
1 SIMPLE packages eq_ref PRIMARY,enddate PRIMARY 4 packagestocity.packageid 1 Using where
1 SIMPLE provider eq_ref PRIMARY,providertype PRIMARY 4 packages.providerid 1 Using where
1 SIMPLE packagestosubcat ref subcatid,packageid packageid 4 packages.id 1 Using where
1 SIMPLE subcat eq_ref PRIMARY PRIMARY 4 packagestosubcat.subcatid 1
1 SIMPLE usertosubcat ref userid,subcatid subcatid 4 const 12 Using where
1 SIMPLE usertoprovider ALL userid,providerid NULL NULL NULL 3735 Using where
正如您在上面的查询中看到的,条件本身是:
provider.providertype = 'reg' OR
(
usertoprovider.userid = 1 AND
provider.providertype != 'reg' AND
usertoprovider.providerid = provider.ID
)
provider 和 usertoprovider 这两个表都已编入索引。 provider 在 providerrid 和 providertype 上有索引,而 usertoprovider 在 userid 和 providerid 上有索引
键的基数是: provider.id=47,provider.type=1,usertopprovider.userid=1245,usertopprovider.providerid=6
所以很明显没有使用索引。
更进一步,为了测试它,我继续:
- 复制了 usertoprovider 表
- 将所有 providertype='reg' 的提供者值插入到克隆表中
- 将条件简化为 (usertoprovider.userid = 1 AND usertoprovider.providerid = provider.ID)
查询执行时间从8.1317秒变为0.0387秒
不过,providertype='reg' 的提供者值对所有用户都有效,我想避免将这些值插入到所有用户的 usertoprovider 表中,因为这些数据是多余的。
谁能解释一下为什么 MySQL 仍然运行完整扫描并且不使用密钥?有什么办法可以避免呢?
【问题讨论】:
-
您能否给出 CREATE TABLE 语句并将您的查询包装在多行中?您可能需要检查索引提示:dev.mysql.com/doc/refman/5.5/en/index-hints.html
-
对不起,我已经整理了资料。
-
嗯...对于这些类型的连接,我真的建议您使用 ANSI-JOIN 语法。只是让事情更具可读性,您可以轻松地将实际谓词与 JOIN 条件分开......
标签: mysql sql optimization indexing