3
在我的Rails應用程序中,我有一些功能可以查找最接近當前登錄用戶的用戶。我爲此使用Geocoder gem。在用戶模型中我有這樣的範圍:添加索引以加快搜索附近的地理編碼器
scope :close_to, -> (user:, distance:) {
where.not(id: user.id)
.near([user.latitude, user.longitude], distance)
}
這很有效,但它對較大的用戶集合很慢。當我稱這個範圍它產生以下SQL查詢:
SELECT users.*, 6371.0 * 2 * ASIN(SQRT(POWER(SIN((48.471645 - users.latitude) * PI()/180/2), 2) + COS(48.471645 * PI()/180) * COS(users.latitude * PI()/180) * POWER(SIN((-83.102801 - users.longitude) * PI()/180/2), 2))) AS distance, MOD(CAST((ATAN2(((users.longitude - -83.102801)/57.2957795), ((users.latitude - 48.471645)/57.2957795)) * 57.2957795) + 360 AS decimal), 360) AS bearing FROM "users" WHERE ("users"."id" != 43362) AND (users.latitude BETWEEN 39.4784289408127 AND 57.46486105918731 AND users.longitude BETWEEN -96.6674214298497 AND -69.5381805701503 AND (6371.0 * 2 * ASIN(SQRT(POWER(SIN((48.471645 - users.latitude) * PI()/180/2), 2) + COS(48.471645 * PI()/180) * COS(users.latitude * PI()/180) * POWER(SIN((-83.102801 - users.longitude) * PI()/180/2), 2)))) BETWEEN 0.0 AND 1000) ORDER BY distance ASC;
我想創建索引,但他們不工作。我正在嘗試以下組合:
1.
add_index :users, [:id, :latitude]
add_index :users, [:id, :longitude]
2. add_index :users, [:id, :latitude, :longitude]
3. add_index :users, [:latitude]
add_index :users, [:longitude]
4. add_index :users, [:id, :latitude]
我應該如何添加索引以加快此查詢?
編輯:我忘了補充說我的經緯度列是小數。
分析這個查詢將返回類似的東西:
Sort (cost=7141.66..7142.14 rows=191 width=327) (actual time=575.995..585.543 rows=36598 loops=1)
Sort Key: ((12742::double precision * asin(sqrt((power(sin((((((48.471645 - latitude))::double precision * 3.14159265358979::double precision)/180::double precision)/2::double precision)), 2::double precision) + ((0.662990616338754::double precision * cos((((latitude)::double precision * 3.14159265358979::double precision)/180::double precision))) * power(sin(((((((-83.102801) - longitude))::double precision * 3.14159265358979::double precision)/180::double precision)/2::double precision)), 2::double precision)))))))
Sort Method: external merge Disk: 4672kB
-> Seq Scan on users (cost=0.00..7134.43 rows=191 width=327) (actual time=0.381..517.615 rows=36598 loops=1)
Filter: ((id <> 43362) AND (latitude >= 39.4784289408127) AND (latitude <= 57.46486105918731) AND (longitude >= (-96.6674214298497)) AND (longitude <= (-69.5381805701503)) AND ((12742::double precision * asin(sqrt((power(sin((((((48.471645 - latitude))::double precision * 3.14159265358979::double precision)/180::double precision)/2::double precision)), 2::double precision) + ((0.662990616338754::double precision * cos((((latitude)::double precision * 3.14159265358979::double precision)/180::double precision))) * power(sin(((((((-83.102801) - longitude))::double precision * 3.14159265358979::double precision)/180::double precision)/2::double precision)), 2::double precision)))))) >= 0::double precision) AND ((12742::double precision * asin(sqrt((power(sin((((((48.471645 - latitude))::double precision * 3.14159265358979::double precision)/180::double precision)/2::double precision)), 2::double precision) + ((0.662990616338754::double precision * cos((((latitude)::double precision * 3.14159265358979::double precision)/180::double precision))) * power(sin(((((((-83.102801) - longitude))::double precision * 3.14159265358979::double precision)/180::double precision)/2::double precision)), 2::double precision)))))) <= 1000::double precision))
Rows Removed by Filter: 6756
Planning time: 1.041 ms
Execution time: 587.695 ms
(8 rows)
編輯2:
我注意到,PostgreSQL使用我的
add_index :users, [:latitude, :longitude]
只有當我鍵入小的距離前
。用戶在近10公里。