2010-06-03 154 views
2

好我的巨人朋友我再次尋求在你肩膀上的小空間:P數據庫查詢優化

這裏的問題,我有一個固定的一些數據庫問題Python腳本,但它走的時間太長,主要更新語句是這樣的:

cursor.execute("UPDATE jiveuser SET username = '%s' WHERE userid = %d" % (newName,userId)) 

,這是獲得所謂的不同了newName和用戶ID對約9500倍......

就如何加快這一進程有什麼建議?也許某種方式可以讓我只用一個查詢就可以完成所有更新?

任何幫助將不勝感激!

PS:Postgres是正在使用的數據庫。

+0

你能發佈的「輸出EXPLAIN ANALYZE 「? – 2010-06-03 17:57:15

+0

你能否介紹一下多久太久了?十秒鐘,五個小時? – Anonymoose 2010-06-06 20:19:26

+0

@Anonymouse我需要它運行在2.5小時,它目前正在採取5 – hdx 2010-06-07 23:20:05

回答

4

插入所有的數據到另一個空表(稱爲userchanges,說的)然後更新單批:

UPDATE jiveuser 
SET username = userchanges.username 
FROM userchanges 
WHERE userchanges.userid = jiveuser.userid 
    AND userchanges.username <> jiveuser.username 

請參閱批量裝載數據上the COPY command本文檔。

還有tips for improving performance when populating a database

+2

製作臨時表格,完成後不必擔心。 – 2010-06-03 19:38:58

+0

@Cade Roux:我更新了你的語句,因爲PostgreSQL的UPDATE ... FROM構造與你寫的有些不同(但足夠接近以至於我只注意到它在第二遍......) – araqnid 2010-06-03 20:40:28

+0

另外,請查看使用COPY將數據推送到服務器,但它需要一些特定於驅動程序的支持(通常稱爲putcopydata或類似的) – araqnid 2010-06-03 20:45:29

2

你可能要考慮executemany():信息here

3

首先,做使用%運算符來構建你的SQL。相反,通過你的參數元組的第二個參數cursor.execute,這也否定了需要引用你的論點,並允許您使用%s的一切:

cursor.execute("UPDATE jiveuser SET username = %s WHERE userid = %s", (newName, userId)) 

這一點很重要,以防止SQL Injection attacks

要回答你的問題,你可以通過創建在userid列的索引,這將允許數據庫在O(1)不斷及時更新,而不必掃描整個數據庫表,這是O(n)加快這些更新。既然你使用PostgreSQL,這裏是創建索引的語法:

CREATE INDEX username_lookup ON jiveuser (userid); 

編輯:由於您的評論表明您已經對userid列的索引,有沒有什麼你可能做,以加快該查詢。所以你的主要選擇或者生活緩慢,因爲這聽起來像是一次性的修復 - 破碎的東西,或者按照VeeArr的建議和測試cursor.executemany是否會給你足夠的提升。

+1

嗯,我有一個用戶名索引,這就是where子句中的內容......用戶名上的索引真的有幫助嗎? – hdx 2010-06-03 17:54:35

+0

@hdx:不,這是我的錯誤,我不小心鍵入了'username'而不是'userid',我沒有意識到你已經有了該列的索引。我剛剛糾正了我的錯字。 – 2010-06-03 18:13:43

+0

它是'%s'每個Postgres DBAPI的佔位符嗎?我不知道,我在問,因爲佔位符通常是「?」。 – tzot 2010-06-04 00:41:21

1

也許你可以在用戶ID上創建一個索引來加快速度。

0

將其移至存儲過程並從數據庫self中執行。

+0

好吧,當你把數據放到臨時表或類似的數據庫中時,你不需要服務器功能。 – araqnid 2010-06-03 20:22:40

1

我會做一個解釋。如果它正在進行索引查找以查找記錄 - 如果您在userid上有索引,那麼它應該是這樣 - 然後我看不到您可以採取哪些措施來提高性能。如果它不使用索引,那麼訣竅就是搞清楚爲什麼不可以修復它。

哦,你可以嘗試使用準備好的語句。有了9500插入,這應該有所幫助。

3

花費這麼長時間的原因可能是您啓用了自動提交功能,並且每次更新都會在自己的事務中完成。

這很慢,因爲即使您擁有電池供電的RAID控制器(當然,您應該在所有數據庫服務器上擁有該控制器),但仍需要對每個事務提交進行寫入,以確保耐用性。

解決方案是對每個事務執行多個行。但是不要讓交易太多,否則你也會遇到問題。嘗試提交每10,000行更改作爲粗略猜測。

0

首先確保您有「用戶ID」的指數,這將確保DBMS不必做每次

CREATE INDEX jiveuser_userid ON jiveuser (userid); 
表掃描

下一頁嘗試準備語句,然後調用執行就可以了。這將從不必每次

PREPARE update_username(string,integer) AS UPDATE jiveuser SET username = $1 WHERE userid = $2; 
EXECUTE update_username("New Name", 123); 

最後檢查查詢停止優化,更多的性能可以通過關閉自動提交

被擠掉
\set autocommit off