使用EXPLAIN
顯示,以下查詢不使用我的索引,可能會有人請解釋一下到底是怎麼回事?MySQL的停止使用索引時,附加的約束添加
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 v5.7開始,[InnoDB支持空間數據類型,但不支持空間索引。](http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html)讓我們忘記那些列包含空間信息,我們將它們視爲「DOUBLE」。運行'EXPLAIN',我可以看到註釋條件列'dateOfBirth',並且下一步'經度'會逐漸減少報告的索引關鍵字長度。我認爲這意味着整個覆蓋索引被有效使用,而不僅僅是「緯度」。你怎麼看? – DTs
@DTs。 。 。覆蓋索引可能仍然只用於獲取列。掃描索引可能比掃描表更快。 –
仍然困惑。我得到的是讀取非索引列所需的數據頁面讀取,但是如果報告的索引關鍵字長度顯示索引的所有3列都被使用,那麼索引的「longitude」和「dataOfBirth」部分如何不被使用用於查找合格行的相應PK?我試圖在文檔中找到你提到的限制_「索引查找只能使用平等條件和一個不等式。」_,你有任何鏈接方便嗎?謝謝。 – DTs