2015-12-31 48 views
0

我需要製作大量SQL查詢來更新或插入使用Psycopg2的行。沒有其他查詢正在中間運行。阿具有列namevalue例如具有表:使用Psycopg2優化一系列SQL更新查詢

% Basically models a list of strings and how many times they "appear" 
% 'foo' is some random value each time, sometimes repeating 
insert into A select ('foo', 0) 
    where not exists(select 1 from A where name = 'foo' limit 1); 
update A set value = value + 1 where name = 'foo'; 
% ... and many more just like this 

這只是一個實例,一種類型的查詢我跑。我也在做其他事情。我不在尋找解決方案,包括重新處理我的SQL查詢。

它真的很慢,Postgres(運行在另一臺服務器上)瓶頸。我已經嘗試了各種各樣的東西來讓它更快。

  • 如果我在每次查詢之後犯下這種情況,這種速度令人難以忍受。
  • 如果我沒有connection.commit()直到最後,它會快一點。這似乎是Psycopg2文檔建議的。 Postgres在磁盤訪問方面仍然存在瓶頸。
  • 如果我使用cursor.mogrify()而不是cursor.execute(),將所有查詢存儲在一個大列表中,並將它們最後加入一個大規模查詢(字面上爲";".join(qs))並運行它,速度會更快。 Postgres使用100%CPU,這是一個好兆頭,因爲這意味着〜沒有磁盤瓶頸。但是,這有時會導致postgres進程耗盡我所有的RAM和初始頁錯誤,從而永久地阻礙磁盤訪問,成爲一場災難。我已經使用pgtune將Postgres的所有內存限制設置爲合理的值,但是我猜測Postgres正在分配一堆沒有限制的工作緩衝區並且繼續。
  • 我已經嘗試了上述解決方案,除了承諾每100,000個查詢以避免超載服務器,但這不會是一個完美的解決方案。這是我現在所擁有的。這似乎是一個可笑的黑客,並且比我想要的還要慢。

有沒有其他方法我應該嘗試涉及Psycopg2?

回答

1

聽起來像你有很多問題在這裏。首先是Postgres不應該錯誤地分頁,除非你配置不當或者你正在計算機上運行其他服務。正確配置的Postgres實例將使用你的內存,但它不會出現頁面錯誤。

如果您需要每次插入或更新100,000個事物,您一定不希望一次執行1次事務,因爲您注意到這將非常緩慢。在你的第一個例子中,你正在通過網絡發送每個查詢到數據庫,等待結果,然後再次通過網絡提交併等待結果。

一次串起多件東西將節省1次提交和來回網絡流量,這就是爲什麼你看到顯着更快的性能。

如果您正在進行插入操作或使用值列表而不是單個插入或更新語句,則可以將字符串放在一起並使用副本。

真正的問題是你在做什麼的設計流程。你在查詢查詢的過程中正在數據庫中實現一個計數器。如果你只是在這裏或那裏計算幾百件事情,沒有什麼大不了的,但是當你進入10萬時+它不會很好。

這就是memcached和redis之類的工具來的地方。兩者都有非常快的內存計數器。 (如果你只有一臺服務器,你可以在你的代碼中實現一個計數器。)一旦你計算了東西,只需創建一個進程來將計數保存到數據庫並清除內存計數器。

+0

忘記我已經在我的處置複製!我正在努力做到這一點。我沒有使用memcached,但我在Python dicts中建立了大量數據(直到RAM變短),將它們複製到臨時表中的數據庫中,然後用一個UPDATE查詢將臨時表與永久表合併在一起。我也有一些更復雜的聚合函數,所以我不得不做一些數學計算如何合併。 – sudo

+0

另外,如果我的數據無法合併,這可能不起作用,可能是因爲某些遞歸函數。例如,如果我保持新值和最後值之間的平均差值......幸運的是,情況並非如此。 – sudo