2014-09-19 28 views
0

我的User表有記錄。我有更新的方法的用戶auth_tokenRails 4 SQL Update耗時太長

def reset_auth_token 
    update_column(:auth_token, generate_token) 
    end 

generate_token方法:

def generate_token 
    token = SecureRandom.urlsafe_base64(23) 
    User.exists?(auth_token: token) ? generate_token : token 
    end 

(我使用update_column因爲正在生成的令牌服務器端我跳過驗證,有沒有回調,並且我不需要用戶updated_at屬性進行更改)

此方法生成的示例SQL是

User Exists (0.5ms) SELECT 1 AS one FROM "users" WHERE "users"."auth_token" = 'XA0syuJg0PGHrAHW78_S3KLGv71_kqY' LIMIT 1 
    SQL (6.3ms) UPDATE "users" SET "auth_token" = 'XA0syuJg0PGHrAHW78_S3KLGv71_kqY' WHERE "users"."id" = 3 

6.3ms !!!只有5個記錄。我已經檢查過,確保沒有爲這個數據庫表啓用觸發器,並且我在auth_token屬性上添加了一個索引(因爲我經常根據該屬性檢查用戶是否存在)。爲什麼更新需要這麼長時間,其他可能的解釋是什麼?

UPDATE

至於建議,我跑的解釋一下:

EXPLAIN UPDATE users SET auth_token = 'foo' WHERE id = '1'; 

            QUERY PLAN 
--------------------------------------------------------------------------------- 
Update on users (cost=0.14..8.15 rows=1 width=4167) 
    -> Index Scan using users_pkey on users (cost=0.14..8.15 rows=1 width=4167) 
     Index Cond: (id = 1) 
(3 rows) 
+0

'解釋(緩衝區,分析)'查詢。我的第一個想法是嚴重的表膨脹。你有沒有機會去關閉PostgreSQL中的autovacuum或以其他方式搞砸了它?我的另一個想法是,在您首次發佈更新時,其他會話鎖定了它。 – 2014-09-19 04:47:48

+0

@CraigRinger我更新了我的答案以顯示解釋的結果。我沒有碰過Postgres,甚至放棄了我的數據庫並重新創建它,以確保沒有其他事情發生。我不明白在你第一次發佈更新時「其他會話鎖定了它」部分? – kittyminky 2014-09-19 06:58:51

回答

0

你可能看到的ACIDD。事務日誌必須到達磁盤上的特定位置,並且需要大約10K rpm的磁盤才能進行輪換。

如果您的用戶無法等待百分之一秒,則可以嘗試關閉該事務的synchronous_commit。

+0

這是在我的應用程序的登錄頁面。我設置了一個自定義的無密碼登錄,所以用戶只需輸入他們的用戶名,就會生成一個新的唯一令牌鏈接,然後通過電子郵件發送給他們,以便他們點擊並登錄。在這種情況下,重要的是它能夠快速工作。我剛剛閱讀文檔'關閉synchronisation_commit可以是一個有用的替代方法,當性能比事務的持久性確切確定更重要'時,在這種情況下可以安全地關閉此功能,因爲電子郵件中的令牌必須與令牌存儲在數據庫? – kittyminky 2014-09-19 20:54:00

+0

這是進口,它在少於6毫秒的工作?我發現很難相信。但無論如何,電子郵件本質上是不可靠的。電子郵件不會經歷的各種原因,然後他們只需要請求另一個令牌(您的系統需要允許)。你引入了一個非常小的可能性,他們會收到一封電子郵件,然後發現它不起作用,因爲數據庫忘記它發送了它。但是,同樣的解決方案,他們需要再試一次,所以它看起來不是一個很大的風險。 – jjanes 2014-09-22 03:08:01