簡體   English   中英

添加其他約束后,MySQL停止使用索引

[英]MySQL stops using index when additional constraints are added

使用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個不同的單部分索引。 根據此處的文檔,優化器是否不應該通過創建其合格行的UNION來合並它們,從而進一步加快執行速度? 它沒有這樣做,它仍然選擇多部分(覆蓋)索引。


任何幫助,不勝感激!

這有點難以解釋。

使用索引的查詢正在使用它,因為該索引是“覆蓋”索引。 也就是說,索引中的所有列都在查詢中。 真正有效使用的索引的唯一部分是latitude條件。

通常,覆蓋索引包含查詢中提到的列。 但是,主鍵用於引用記錄,因此我猜到users.Id是表上的主鍵。 並且正在掃描索引以查找有效的latitude值。

不使用索引的查詢未使用索引有兩個原因。 首先,列上的條件是不等式。 索引查找只能使用相等條件和一個不相等。 這意味着該索引只能以其最有效的方法用於latitude 其次,無論如何查詢中的其他列都需要轉到數據頁面。

換句話說,優化器實際上是在說:“為什么要麻煩索引以遍歷索引然后再掃描數據頁?相反,我可以只掃描數據頁並立即獲得所有內容。”

毫無疑問,您的下一個問題是:“但是,如何使查詢速度更快?” 我的建議是研究空間指數

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM