简体   繁体   中英

How to excecute multiple SQL queries to pandas dataframes in parallel

Hi all Python Pandas gurus. I'm looking for a way to run some SQL in parallel with Python, returning several Pandas dataframes. I have code similar to below that serially runs 4 SQL queries against a MS SQL server database. Two of the queries have much longer execution time vs. IO (network) time to get the results, so I'm thinking parallelizing would make the code run ~2x faster. Is there an easy way to execute the queries in parallel?

Ideally, I would like to be able to read all the *.sql files in a sub dir of a project, then fire off the queries to run in parallel and return the four dataframes in a easy to use format (list?) for further operations (indexing, joining, aggregating).

Thanks in advance, Randall

# imports
import ceODBC
import numpy as np
import pandas as pd
import pandas.io.sql as psql
from ConfigParser import ConfigParser  
import os
import glob

# db connection string
cnxn = 'DRIVER={SQL Server Native Client 11.0}; SERVER=<servername>; DATABASE=<dname>; Trusted_Connection=Yes'

# directories (also should be moved to config)
dataDir = os.getcwd() + '\\data\\'
sqlDir = os.getcwd() + '\\sql\\'

# read sql from external .sql files. Possible to read all *.sql files in a sql dir into a list (or other structure...)?
with open(sqlDir + 'q1.sql', 'r') as f: q1sql = f.read()
with open(sqlDir + 'q2.sql', 'r') as f: q2sql = f.read()
with open(sqlDir + 'q3.sql', 'r') as f: q3sql = f.read()
with open(sqlDir + 'q4.sql', 'r') as f: q4sql = f.read()

# Connect to db, run SQL, assign result into dataframe, close connection. 
cnxn = ceODBC.connect(cnxn)
cursor = cnxn.cursor()

# execute the queries and close the connection. Parallelize?
df1 = psql.frame_query(q1sql, cnxn)
df2 = psql.frame_query(q2sql, cnxn) 
df3 = psql.frame_query(q3sql, cnxn)
df4 = psql.frame_query(q4sql, cnxn) 

# close connection
cnxn.close()

Use N of connections in N threads. Then join theads and procces results.

# imports
import ceODBC
import numpy as np
import pandas as pd
import pandas.io.sql as psql
from ConfigParser import ConfigParser  
import os
import glob
import threading
enter code here


# db connection string
cnxn_string = 'DRIVER={SQL Server Native Client 11.0}; SERVER=<servername>; DATABASE=<dname>; Trusted_Connection=Yes'

# directories (also should be moved to config)
dataDir = os.getcwd() + '\\data\\'
sqlDir = os.getcwd() + '\\sql\\'

#variable to store results
responses={}
responses_lock=threading.Lock()

maxconnections = 8
pool_sema = BoundedSemaphore(value=maxconnections)


def task(fname):

    with open(fname, 'r') as f: sql = f.read()

    # Connect to db, run SQL, assign result into dataframe, close connection. 
    # to limit connections on DB used semaphore
    pool_sema.acquire()
    cnxn = ceODBC.connect(cnxn_string)
    cursor = cnxn.cursor()
    # execute the queries and close the connection. Parallelize?
    df = psql.frame_query(sql, cnxn)
    # close connection
    cnxn.close()
    pool_sema.release()

    # to ensure that only one thread can modify global variable
    responses_lock.acquire()
    responses[fname] = df
    responses_lock.release()


pool = []

#find sql files and spawn theads
for fname im glob.glob( os.path.join(sqlDir,'*sql')):
    #create new thread with task
    thread = threading.Thread(target=task,args=(fname,))
    thread.daemon = True
    # store thread in pool 
    pool.append(thread)
    #thread started
    thread.start()

#wait for all threads tasks done
for thread in pool:
    thread.join()

# results of each execution stored in responses dict

Each file executes in separate thread. Result stored in one variable.

Equivalent for function with with statement:

def task(fname):

    with open(fname, 'r') as f: sql = f.read()

    # Connect to db, run SQL, assign result into dataframe, close connection. 
    # to limit connections on DB used semaphore
    with pool_sema:
        cnxn = ceODBC.connect(cnxn_string)
        cursor = cnxn.cursor()
        # execute the queries and close the connection. Parallelize?
        df = psql.frame_query(sql, cnxn)
        # close connection
        cnxn.close()


    # to ensure that only one thread can modify global variable
    with responses_lock:
        responses[fname] = df

multiprocessing.Pool is easy for distributing heavy tasks, but has more IO operations in it self.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM