【发布时间】:2014-08-03 09:22:15
【问题描述】:
使用EXPLAIN 表明以下查询不使用我的索引,有人可以解释一下是怎么回事吗?
SELECT u.id AS userId, firstName, profilePhotoId, preferredActivityId, preferredSubActivityId, availabilityType,
3959 * ACOS(COS(radians(requestingUserLat)) * COS(radians(u.latitude)) * COS(radians(u.longitude) - radians(requestingUserLon)) + SIN(radians(requestingUserLat)) * SIN(radians(u.latitude))) AS distanceInMiles
FROM users u
WHERE u.latitude between lat1 and lat2 -- MySQL 5.7 supports Point data type, but it is not indexed in innoDB. I store latitude and longitude as DOUBLE for now
AND u.longitude between lon1 and lon2
AND u.dateOfBirth between maxAge and minAge -- dates are in millis, therefore maxAge will have a smaller value than minAge and so it needs to go first
AND IF(gender is null, TRUE, u.gender = gender)
AND IF(activityType is null, TRUE, u.preferredActivityType = activityType)
AND u.accountState = 'A'
AND u.id != userId
HAVING distanceInMiles < searchRadius ORDER BY distanceInMiles LIMIT pagingStart, pagingLength;
CREATE INDEX `findMatches` ON `users` (`latitude` ASC, `longitude` ASC, `dateOfBirth` ASC) USING BTREE;
在这个阶段根本不使用索引。为了让它工作,我需要从SELECT 语句中注释掉一堆列,并从WHERE 子句中删除所有未索引的列。以下作品:
SELECT u.id AS userId --, firstName, profilePhotoId, preferredActivityId, preferredSubActivityId, availabilityType,
3959 * ACOS(COS(radians(requestingUserLat)) * COS(radians(u.latitude)) * COS(radians(u.longitude) - radians(requestingUserLon)) + SIN(radians(requestingUserLat)) * SIN(radians(u.latitude))) AS distanceInMiles
FROM users u
WHERE u.latitude between lat1 and lat2 -- MySQL 5.7 supports Point data type, but it is not indexed in innoDB. We store latitude and longitude as DOUBLE for now
AND u.longitude between lon1 and lon2
AND u.dateOfBirth between maxAge and minAge -- dates are in millis, therefore maxAge will have a smaller value than minAge and so it needs to go first
-- AND IF(gender is null, TRUE, u.gender = gender)
-- AND IF(activityType is null, TRUE, u.preferredActivityType = activityType)
-- AND u.accountState = 'A'
-- AND u.id != userId
HAVING distanceInMiles < searchRadius ORDER BY distanceInMiles LIMIT pagingStart, pagingLength;
我尝试过的其他方法:
除了包含所有 3 个键的多部分索引之外,我还尝试创建 3 个不同的单部分索引。根据文档here,优化器不应该通过创建符合条件的行的 UNION 来合并它们,从而进一步加快执行速度吗?它不这样做,它仍然选择多部分(覆盖)索引。
非常感谢任何帮助!
【问题讨论】:
标签: mysql sql indexing query-optimization