python從資料庫獲取全量資料的方法
阿新 • • 發佈:2019-02-03
資料庫:postgresql
(1)第一種方法:使用分頁查詢的方式,不推薦使用特別是在資料量大的時候
首先計算總資料量,然後根據每次查詢的大小batch_size計算總共有多少頁,再一頁一頁的去獲取資料。
由於分頁查詢類似ES中的深度分頁,頁數越大效率越低,因此在資料量小的時候用用還湊合。
import psycopg2.pool from datetime import datetime # 資料庫連線 conn = psycopg2.connect(database="dbname", user="username", password="123456", host="172.0.0.0", port="5432") # 獲取遊標 cursor = conn.cursor() # 批量查詢大小 batch_size = 1000 def limit_offset_query(): """ 分頁查詢 :return: """ # 資料總量 total_count = get_total_count() if total_count <= 0: return # 總頁數 total_page = total_count / batch_size # 開始時間 start_time = datetime.now() for i in range(int(total_page) + 1):# 遍歷每一頁 # 起始位置 start = batch_size * i # 查詢資料 result_list = get_tweet_by_page(start, batch_size) if (len(result_list) > 0): print('獲取%s到%s資料成功' % (start, start + batch_size)) print('limit offset獲取全量資料所用時間:', (datetime.now() - start_time).seconds) def get_total_count(): """ 分頁查詢獲取總數量 :return: """ sql = "select count(*) from tablename" cursor.execute(sql) rst = cursor.fetchone() if rst is None: return 0 return rst[0] def get_tweet_by_page(start, pagesize): """ 分頁查詢 :param start: :param pagesize: :return: """ sql = "select * from tablename limit %s offset %s " cursor.execute(sql, [pagesize, start]) rst = cursor.fetchall() return rst limit_offset_query()
(2)第二種方式,使用遊標fetchmany方法,獲取全量資料,在大資料量下推薦使用
fetchmany方法接受一個size引數,fetchmany每次呼叫的時候從上次的位置向後移動遊標返回size條資料。
參考文件中的例子:
從test表中獲取全部資料,一共有3條資料:
第一次呼叫fetchmany引數返回兩條資料,遊標移動兩個位置。
第二次呼叫fetchmany雖然size傳入為2,但是隻剩一條資料,因此返回一條資料,遊標向後移動一個位置。
第三次呼叫fetchmany方法時由於資料已經全部返回,因此返回空資料。
>>> cur.execute("SELECT * FROM test;") >>> cur.fetchmany(2) [(1, 100, "abc'def"), (2, None, 'dada')] >>> cur.fetchmany(2) [(3, 42, 'bar')] >>> cur.fetchmany(2) []
關於服務端遊標server side curosr和客戶端遊標client side cursor:
根據文件的描述,通過資料庫連線建立遊標的時候,如果傳入name引數,就會返回一個服務端遊標,如果name引數為空,返回的則是一個客戶端遊標,如果返回的結果集數量比較大,應該使用服務端遊標。
測試資料大概有100萬,剛開始name引數為空執行程式的時候直接記憶體飆升,pycharm卡頓,可能就是因為返回的是客戶端遊標,客戶端遊標只能處理小量資料。
import psycopg2.pool from datetime import datetime # 批量查詢大小 batch_size = 1000 def cursor_query(): # 使用資料庫連線池,使用普通的連線方法執行貌似也會記憶體飆升,因此改為了連線池 simple_conn_pool = psycopg2.pool.SimpleConnectionPool(minconn=1, maxconn=5, database="dbname", user="username", password="123456", host="172.0.0.1", port="5432") # 從資料庫連線池獲取連線 conn = simple_conn_pool.getconn() # 自動提交事務設為false conn.autocommit = False # 建立遊標,這裡傳入name引數,會返回一個服務端遊標否則返回的是客戶端遊標 cursor = conn.cursor('cursorname') # 首先查詢全量資料 cursor.execute('select * from tablename') count = 0 # 開始時間 start_time = datetime.now() while True: count = count + 1 # 每次獲取時會從上次遊標的位置開始移動size個位置,返回size條資料 data = cursor.fetchmany(batch_size) # 資料為空的時候中斷迴圈 if not data: break print('獲取%s到%s資料成功' % ((count - 1) * batch_size, count * batch_size)) print('fetchmany獲取全量資料所用時間:', (datetime.now() - start_time).seconds) cursor_query()
資料表大概有100萬資料,分別用兩種方法測試了一下時間:
使用limit offset分頁查詢耗時321s:
limit offset獲取全量資料所用時間:321
使用fetchmany方法耗時122s:
fetchmany獲取全量資料所用時間: 122