【问题标题】:Optimizing MS SQL insert via pyodbc通过 pyodbc 优化 MS SQL 插入
【发布时间】:2019-04-26 16:52:53
【问题描述】:

我正在捕获来自 API 调用的 JSON 响应并插入到 MS SQL 数据库中。 API 总共有大约 500,000 个数据条目,我一次可以查询 1000 个。

SQL 插入查询语句似乎花费了太长时间,我假设它可能与我的查询连接和字符串转换有关。

SQL 列

self.query_headers = "([ac_serial_reg_key],[activity_date], 
    [aircraft_delivery_date],[activity_name],[activity_remark],
    [aircraft_category],[aircraft_financial_status],[aircraft_group],
    [aircraft_model],[aircraft_operational_status],[aircraft_registration_number], [aircraft_serial_number],
    [aircraft_type],[engine_model],[engine_type],[operator_name]
)"

然后通过迭代 JSON 响应来组合 SQL 值

self.query_values = ''

for idx, set in enumerate(self.response.json()['results'], start=1):
    self.query_values += "("
    self.query_values += "'"+str(set['aircraft_registration_number'])+"_"+str(set['aircraft_serial_number'])+"',"
    self.query_values += self.validate_date(set['activity_date'])+","
    self.query_values += self.validate_date(set['aircraft_delivery_date'])+","
    self.query_values += "'"+str(set['activity_name'])+"',"
    self.query_values += "'"+str(set['activity_remark'])+"',"
    self.query_values += "'"+str(set['aircraft_category'])+"',"
    self.query_values += "'"+str(set['aircraft_financial_status'])+"',"
    self.query_values += "'"+str(set['aircraft_group'])+"',"
    self.query_values += "'"+str(set['aircraft_model'])+"',"
    self.query_values += "'"+str(set['aircraft_operational_status'])+"',"
    self.query_values += "'"+str(set['aircraft_registration_number'])+"',"
    self.query_values += "'"+str(set['aircraft_serial_number'])+"',"
    self.query_values += "'"+str(set['aircraft_type_lar'])+"',"
    self.query_values += "'"+str(set['engine_model'])+"',"
    self.query_values += "'"+str(set['engine_type'])+"',"
    self.query_values += "'"+str(set['operator_name'])+"'"
    self.query_values += ")"                    

if idx < self.response.json()['results_this_page']:
    self.query_values += ","

如何最好地解析返回的 JSON 对象以创建单个(或多个)插入语句?

插入声明

self.query = "INSERT INTO "+self.database+" "+self.query_headers+" VALUES"+self.query_values
self.cursor.execute(self.query)
self.cnxn.commit()

【问题讨论】:

  • 我不会打扰;我会将 JSON 作为 NVARCHAR(max) 发送到数据库并让数据库对其进行解包 - 它肯定比在您的客户端应用程序中解包 500,000 个 json 实体并运行半百万个插入语句要快。
  • 绝对值得调查,@CaiusJard 有一个参考链接让我了解如何做到这一点?
  • docs.microsoft.com/en-us/sql/relational-databases/json/… 很不错,为了帮助更多,发布一些示例 json 和表格规范

标签: json sql-server python-3.x pyodbc


【解决方案1】:

从我的 cmets 中的链接来看,像这样可以快速将数十万个 json 值插入到一个表中:

JSON: 
N'[  
       { "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 },  
       { "id" : 5,"info": { "name": "Jane", "surname": "Smith", "skills": ["SQL", "C#", "Azure"] }, "dob": "2005-11-04T12:00:00" }  
 ]'  

您将参数化您的 SQL 脚本,以便您的前端应用程序填充 @json 变量(我不知道这在 python 中是什么样的,抱歉,但它与任何参数化的 sql 相同)。这是脚本

INSERT INTO Person(id, fn, ln, age, dob, skill)
SELECT *  
FROM 
  OPENJSON(@json)  
  WITH (id int 'strict $.id',  
        firstName nvarchar(50) '$.info.name', 
        lastName nvarchar(50) '$.info.surname',  
        age int, 
        dateOfBirth datetime2 '$.dob',
        skills nvarchar(max) '$.info.skills' as json) 
  OUTER APPLY 
    OPENJSON( skills ) --to "recurse" into the skills array
    WITH( skill nvarchar(8) '$' )

需要注意的是,outerapply 会导致 Jane Smith 的人员数据重复,每个技能一次:

5, Jane, Smith, ..., C#
5, Jane, Smith, ..., SQL
5, Jane, Smith, ..., Azure

也许你的 json 没有这个结构。如果是这样,您可以将其打包(不要外部应用)或使用 WHERE 去除无趣的东西:

INSERT INTO Person(id, fn, ln, age, dob, skill)
SELECT *  
FROM 
  OPENJSON(@json)  
  WITH (
         ...
        skills nvarchar(max) '$.info.skills' as json) 
  OUTER APPLY 
    OPENJSON( skills ) --to "recurse" into the skills array
    WITH( skill nvarchar(8) '$' 
WHERE skill = 'C#'

【讨论】:

猜你喜欢
  • 2019-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-18
  • 2015-08-28
  • 2011-05-07
  • 1970-01-01
相关资源
最近更新 更多