Python 遍歷 Mysql 表中資料
阿新 • • 發佈:2018-12-24
需求
Mysql 表中存在幾千萬到幾億的資料(不存在自增主鍵),需要對錶中資料進行遍歷。
使用的是 pymysql
模組。
方案 1
使用 limit
來分塊返回資料。
劣勢:使用 limit
每次都需要從頭掃描資料表,在資料量超過 1000w 時,效能較低。
LIMIT = 5000
def get_name(sql_client, table_name):
i = 0
while True:
sql.ping()
cur = sql.cursor()
sql_cmd = 'select did from {} limit {}, {}' .format(table_name, i * LIMIT, LIMIT)
rt = cur.execute(sql_cmd)
rt_list = cur.fetchall()
cur.close()
yield [rt_tuple[0] for rt_tuple in rt_list]
if rt < LIMIT:
yield 0
i += 1
方案 2
使用 pymysql
中的流式遊標 SSCursor
,流式遊標將執行結果卡在網路緩衝區,當網路緩衝區堆滿時 Mysql 將查詢暫停,當網路快取區有位置時,將會在上次暫停的地方繼續讀取。
def mysql_connect():
mysql_client = pymysql.connect(**SQL_CONFIG)
cur = mysql_client1.cursor()
# 設定超時時間
cur.execute('set session net_write_timeout = 800')
cur.close()
return mysql_client
def get_name(mysql_client, table_name):
sscur = mysql_client.cursor(pymysql.cursors.SSCursor)
sscur.execute('select name from {}' .format(table_name))
i = 0
for name in sscur:
i += 1
yield i, name[0]
mysql_client.commit()
sscur.close()
yield i, 0
問題:
1. 當資料較多時,Mysql 不能在預設的 net_write_timeout
的時間將資料全部發送到客戶端時,程式會丟擲 error2013 , “Lost connection to MySQL server during query
異常,所以修改 Mysql 會話級別的 net_write_timeout
時間,具體數值根據業務處理時間設定。
2. 當個會話正在返回資料的時候不能再對資料庫進行其他操作,程式會發出警告 warnings.warn("Previous unbuffered result was left incomplete")
,並且會伴隨著查詢資料返回出問題。如果此時還需要同時對資料庫進行操作,需另外建立會話。