2018年5月23日 星期三
Devise 每次都會同時下 ORDER BY 和 LIMIT 的 sql 去找 users
同事提出的建議:
```
SELECT "users".* FROM "users" WHERE "users"."id" = $? ORDER BY "users"."id" ASC LIMIT $?
id 是 primary key, 理論上不會有重複的資料.
SELECT id, COUNT(id) AS cid FROM users GROUP BY id ORDER BY cid DESC;
id | cid
--------+-----
1 | 1
58291 | 1
(以下省略)
也確認目前的資料中, 的確沒有出現重複的 id.
這個 query 的 ORDER BY 跟 LIMIT 確認不會被 pgsql 的 query plan / optimizer 省略掉, 還是會產生 procedure call 消耗些微的 cpu / memory, 所以還是建議修改這個 query.
```
查了一下主要罪魁禍首是
Devise::Models::Authenticatable.serialize_from_session
這個 method 是每次已登入的 user 訪問頁面時就會 trigger 的,裡面用了 User.to_adapter.get([id]) 的方式來拿資料
```
:014 > User.to_adapter.get([1])
User Load (2.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
```
另外比較不重要但是也會影響的地方就是登入時的驗證,確切來說就是 Devise::Models::DatabaseAuthenticatable.find_for_database_authentication ,裡面用了 to_adapter.find_first
```
:005 > User.to_adapter.find_first(id: 1)
User Load (1.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
```
可以參考的解法:
* customize serializer: https://github.com/plataformatec/devise/wiki/How-to:-Write-your-own-serializer
* overwrite, ex:
```
class User < ApplicationRecord
def self.serialize_from_session(key, salt)
record = find_by(id: key)
record if record && record.authenticatable_salt == salt
end
end
```
* 想辦法在不必要驗證的地方 skip 上述 find user 的 middelware
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言