1. 程式人生 > >Python 遍歷 Mysql 表中資料

Python 遍歷 Mysql 表中資料

需求

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"),並且會伴隨著查詢資料返回出問題。如果此時還需要同時對資料庫進行操作,需另外建立會話。