2014-11-13 84 views
2

我使用jaydebeapi鍵(Mac OS X)來查詢Netezza公司數據庫,並執行一些快速/骯髒的時機:Python的SQL查詢性能

t0 = time.time() 
curs.execute('''select * from table1;''') 
print time.time() - t0 

我創建了表自己,它包含65萬行9列(整數和日期)。

當我運行上面的命令大約需要1.3分鐘完成(平均超過10次運行)。

然後,當我試圖獲取數據:

t0 = time.time() 
curs.execute('''select * from table1;''') 
row = curs.fetchone() 
while row is not None: 
    row = curs.fetchone() 
print time.time() - t0 

大約需要10分鐘即可完成(平均超過10次)。

現在,當我使用WinSQL(Windows 7,ODBC)運行相同的SQL查詢時,大約需要3分鐘才能返回數據。我似乎無法弄清楚它爲什麼要花更長的時間在Python中,我不知道如何或從哪裏開始尋找。

+0

你在使用什麼驅動程序?它有任何設置嗎?順便說一句,你真的需要完全用Python獲取和處理650k行,沒有任何SQL? – 9000

+0

對於Mac OS X,它的JDBC驅動程序(據我所知,Mac上不存在ODBC)和Windows 7的ODBC驅動程序。不知道這是否回答您的問題,但我將使用Pandas進行切片和切塊。 – slaw

+0

如果您打算使用熊貓,您可能只需要將數據直接讀入Pandas DF。看到這個例子:http://stackoverflow.com/a/12060886/1216837 – ACV

回答

1

您可能想使用curs.fetchmany()而不是fetchone。這將有所優化,來回取回行。

像這樣的事情,甚至會隱瞞事實,你是一次讀取許多行:

def fetchYield(cursor): 
     li = [] 
     while True: 
      if not li: 
       li = cursor.fetchmany() 
       if not li: 
        raise StopIteration 
      yield li.pop(0) 

for row in fetchYield(curs): 
    <do something with row> 

但是,我認爲,如果一個原始的SQL查詢工具需要3分鐘,以獲取數據,它是並不是完全不合理的讓你的Python代碼需要3倍的時間。

+0

但是,大概也應該指定多少行,對吧?否則,它默認爲1,並且與fetchone()相同?至少這是我爲jaydebeapi看到的行爲。 – slaw

+0

我不這麼認爲。我相信在大多數Python db api v2實現中,對於fetchmany有一個默認的「獲取大小」。請參閱http://legacy.python.org/dev/peps/pep-0249/#cursor-methods。您可以在第一次迭代中始終執行print len(li)以查看返回的行數。無論如何,你自己指定一個默認值100。 def fetchYield(cursor,fetchsize = 100)。例如,fetchmany(fetchsize)。 –

2

您是否將JayDeBeApi與JPype結合使用或與Jython一起使用?使用JPype實現獲取大型結果集會導致一些JNI調用導致批量開銷的每個單元值。 您應該考慮以下選項之一:

  1. 最小化結果集的大小。使用SQL函數進行聚合。
  2. 試試最新的JPype1。有一些性能改進。
  3. 將您的運行時切換到Jython(JayDeBeApi也適用於Jython)
  4. 直接在Java中實現db查詢和數據提取,並使用JPype調用邏輯,但使用接口不返回大型數據集。
  5. 嘗試改善JPypeJayDeBeApi代碼
+0

是的,我將JayDeBeApi與JPype結合使用,因爲這是我能找到的例子。你能指點我一些使用JayDeApi設置JPype1的例子嗎? 「將您的運行時切換到Jython」是什麼意思? – slaw

+0

JPype1是否適用於Python 2.7? – slaw

+0

而不是使用'pip install JPype'安裝JPype,你可以通過'pip install JPype1'安裝它。 JPype1是JPype的官方開發,可用於Python 2.7。 – bastian

0

我有一個類似的問題,我使用fetchall和設置光標arraysize參數(detault到1)觀察到的改進,如在DB-API documentation報告了其JayDeBeApi基於。

cursor = conn.cursor() 
cursor.arraysize = 10000 
cursor.execute("select * from table1") 

rows = cursor.fetchall() 

# storing data in a pandas DataFrame 
df = pd.DataFrame(data=rows, columns = ["C1", "C2", "C3"]) 

cursor.close() 

我觀察到位於600.000行取

arraysize = 10000 --- 509 seconds 
arraysize = 1  --- 526 seconds 

不過,我還觀察到一個更大的抓取時間相比,例如下面的演出,一個基於Java的客戶端使用相同的JDBC驅動程序。正如9000所說的,我的建議是花費一些時間在SQL查詢上並讓數據庫完成工作,這是一個更快,更具可擴展性的解決方案。