SQLAlchemy Core选择查询比原始SQL慢得多

时间:2018-09-07 14:46:46

标签: python sql-server performance sqlalchemy

我使用Python3代码运行Jupyter笔记本已有相当长的一段时间了。它结合使用了pyodbc和SQLAlchemy来连接到我公司内部网上的一些SQL Server数据库。笔记本的用途是从初始SQL Server数据库中提取数据,并将其作为Pandas数据框存储在内存中。然后,该文件从其中一列中提取特定值,然后将该值列表发送到两个不同的SQL Server数据库中,以拉回映射列表。

在我决定将原始SQL查询重写为SQLAlchemy Core语句之前,所有这些工作一直很好。我已经经历了验证SQLAlchemy查询可编译以匹配原始SQL查询的过程。但是,查询运行速度异常缓慢。例如,初始原始SQL查询在25秒内运行,而在SQLAlchemy Core中重写的同一查询在15分钟内运行!其余查询即使运行了2个小时也没有完成。

这可能与我反映现有表的方式有关。我什至花了一些时间重写表上的ForeignKey和primary_key,希望这有助于提高性能。没有骰子。

我也知道“如果它没有破裂,请不要修复它”。但是,SQLAlchemy看起来比讨厌的硬编码SQL块好得多。

任何人都可以解释为什么SQLAlchemy查询运行如此缓慢的原因。 SQLAlchemy文档没有提供太多见识。我正在运行SQLAlchemy 1.2.11版。

import sqlalchemy
sqlalchemy.__version__
'1.2.11'

这是相关的行。为了简洁起见,我将出口排除在外,但万一有人需要看到我会很乐意提供的话。

engine_dr2 = create_engine("mssql+pyodbc://{}:{}@SER-DR2".format(usr, pwd))
conn = engine_dr2.connect()

metadata_dr2 = MetaData()
bv = Table('BarVisits', metadata_dr2, autoload=True, autoload_with=engine_dr2, schema='livecsdb.dbo')
bb = Table('BarBillsUB92Claims', metadata_dr2, autoload=True, autoload_with=engine_dr2, schema='livecsdb.dbo')

mask = data['UCRN'].str[:2].isin(['DA', 'DB', 'DC'])
dr2 = data.loc[mask, 'UCRN'].unique().tolist()

sql_dr2 = select([bv.c.AccountNumber.label('Account_Number'),
                  bb.c.UniqueClaimReferenceNumber.label('UCRN')])
sql_dr2 = sql_dr2.select_from(bv.join(bb, and_(bb.c.SourceID == bv.c.SourceID,
                                               bb.c.BillingID == bv.c.BillingID)))
sql_dr2 = sql_dr2.where(bb.c.UniqueClaimReferenceNumber.in_(dr2))

mapping_list = pd.read_sql(sql_dr2, conn)
conn.close()

应与sql_dr2匹配并进行小范围拆分的原始SQL查询在这里:

"""SELECT Account_Number = z.AccountNumber, UCRN = y.UniqueClaimReferenceNumber 
FROM livecsdb.dbo.BarVisits z 
INNER JOIN 
livecsdb.dbo.BarBillsUB92Claims y
ON 
y.SourceID = z.SourceID 
AND 
y.BillingID = z.BillingID
WHERE
y.UniqueClaimReferenceNumber IN ({0})""".format(', '.join(["'" + acct + "'" for acct in dr2]))

列表dr2通常包含多达70,000个元素。同样,原始SQL可以在一分钟或更短的时间内完成处理。现在,SQLAlchemy重写已运行8个多小时,但仍未完成。

更新 下面提供了其他信息。我不是数据库或表的所有者,它们包含受保护的健康信息,因此不是我可以直接共享的信息,但我会看到有关制作一些模拟数据的信息。

tables = ['BarVisits', 'BarBillsUB92Claims']
for t in tables:
    print(insp.get_foreign_keys(t))
[], []

for t in tables:
    print(insp.get_indexes(t))
[{'name': 'BarVisits_SourceVisit', 'unique': False, 'column_names': ['SourceID', 'VisitID']}]
[]

for t in tables:
    print(insp.get_pk_constraint(t))
{'constrained_columns': ['BillingID', 'SourceID'], 'name': 'mtpk_visits'}
{'constrained_columns': ['BillingID', 'BillNumberID', 'ClaimID', 'ClaimInsuranceID', 'SourceID'], 'name': 'mtpk_insclaim'}

在此先感谢您的见解。

1 个答案:

答案 0 :(得分:0)

我想出了如何使查询快速运行的方法,但是不知道为什么此服务器而不是其他服务器需要它。

参加

sql_dr2 = str(sql.compile(dialect=mssql.dialect(), compile_kwargs={"literal_binds": True}))

并通过

发送
pd.read_sql(sql_dr2, conn)

大约2秒钟执行查询。

再次,我不知道为什么行得通,但是行得通。