更新两个不同表中的字段的最有效方法?

Posted

技术标签:

【中文标题】更新两个不同表中的字段的最有效方法?【英文标题】:The most efficient way to update fields in two different tables? 【发布时间】:2016-09-09 19:06:04 【问题描述】:

我正在做一个项目,我必须更新两个不同表中的字段。首先,我使用 .csv 文件读取某些字段的值,然后检查 if 语句中的值,然后进行更新。以前在旧代码中这很容易,因为我只有一个表和一个字段要更新,现在我有两个不同的表和两个字段。仅进行更新很容易,但我有超过 15,000 条记录。我想知道最有效的方法是什么?如果我放置两个单独的查询并运行两次更新,则将运行近 3 万条记录。有没有办法一次做到这一点?如果不是,运行这些更新的最佳方法是什么?这是我用来在 ColdFusion 服务器上运行更新的代码:

<cfset updateFile = "C:\MyFiles\Records.csv">

<cffile action="read" file="#updateFile#" variable="recordsFile">
<cfset myarray = ListToArray(recordsFile, chr(13))>
<cfset cnt = ArrayLen(myarray)>

<cfloop index="i" from="1" to=#(cnt)# step="1">
    <cfif len(trim(myarray[i])) GT 0>
        <cfset myrow = #replace(myarray[i],chr(10),'')#>
        <cfset myrow = ListToArray(myrow,",",true)>

        <cfif #myrow[23]# EQ '1'>
            <cfset #myrow[23]# = 'A'>
        </cfif>

        <cfif #myrow[23]# EQ '2'>
            <cfset #myrow[23]# = 'B'>
        </cfif>

        <cfif #myrow[23]# EQ '3'>
            <cfset #myrow[23]# = 'D'>
        </cfif> 

        <cfquery name="UpdateRecords" datasource="test">
            Update Users
            Set FiledCode = '#myrow[23]#'
            Where User_Number = #myrow[1]#
        </cfquery>  

        <cfoutput>#myrow[1]#</cfoutput><br>
    </cfif>
</cfloop> 

您可以在上面看到我的旧代码的外观,现在我必须再添加一个表并在该表中更新文件,但仍然从同一文件(Records.csv)中读取数组中不同位置的信息。我之前做过更新/插入,但从来没有大量的记录。现在我必须要什么来提高效率并找到最好的方法。如果您对此问题有任何建议,请告诉我。谢谢你。

【问题讨论】:

尽量减少使用 ColdFusion 进行数据处理。另外,使用临时表。如果 mysql 有批量加载程序,请使用它来填充临时表。如果没有,请使用 ColdFusion。然后从临时表更新其他表。 @DanBracuk 我从不使用批量加载程序。你能提供任何例子来回答你的问题吗?谢谢。 我根本不使用 MySQL,这就是为什么我说“如果 MySQL 有批量加载器”。从一个表写入另一个表的语法可在 Internet 上找到。这取决于您是在执行插入、删除还是更新。 【参考方案1】:

另一种解决方案。正如您所说,记录可以更高(高达 30K),存储过程似乎是一个更好的选择。你可以这样做: 首先使用cfftpCSV 文件上传到MySQL 服务器上的某个位置(如果CF 和MySQL 在不同的位置)。 如果 MySQL 与 CF 位于同一位置,则可以跳过上述步骤。

创建一个存储过程来更新所需的表,其中包含所需的逻辑。 大致思路如下: 创建一个临时表,例如temp_update_table,其中包含您需要的列。像这样:

CREATE TEMPORARY TABLE temp_update_table (meta_key, meta_value)

现在使用 LOAD DATA INFILE 将 csv 数据插入到临时表中,如下所示:

LOAD DATA INFILE 'your_csv_pathname' 
INTO TABLE temp_update_table FIELDS TERMINATED BY ';' (meta_key, meta_value); 

然后像这样更新所需的表:

UPDATE "table"
INNER JOIN temp_update_table on temp_update_table.meta_key = "table".meta_key
SET "table".meta_value = temp_update_table.meta_value;

DROP TEMPORARY TABLE temp_update_table;

CSV上传完成后,使用cfstoredproc标签调用上述存储过程。它会更有效率。 Reference

更新 使用存储过程的一些好处包括:

可维护性:您可以更改程序中的逻辑,而无需 需要编辑 app1、app2 和 app3 调用。 安全/访问控制:担心谁可以调用预定义的过程比控制谁可以访问哪些表或哪些表行更容易。 性能 (1​​):如果您的应用与您的应用不在同一台服务器上 DB,而您正在做的事情涉及多个查询,使用 过程通过涉及单个调用来减少网络开销 数据库,而不是与查询一样多的调用。在您的情况下,使用内联查询将访问数据库服务器 30K 次(对于 30K 记录)。 性能 (2):过程的查询计划通常被缓存, 允许您一次又一次地重复使用它,而无需重新准备它。

Read this

【讨论】:

基本上我会将 .csv 中的所有记录存储到临时表中,然后从该表中进行更新?另外我不明白使用 cfstoreproc 的目的和目的是什么?你能再解释一次吗?谢谢。 从创建临时表到删除临时表以及条件逻辑的所有代码都将进入存储过程。 SP 的目的是什么,请阅读更新。【参考方案2】:

最重要的是确保您在表上正确设置了索引,但之后仍有效率提升。

在这种情况下,最大的收益可能来自于减少对数据库的调用次数,即:减少cfquery 标记的数量。例如,您可以将两个表的更新语句放在同一个查询标记中。

<cfquery name="UpdateRecords" datasource="test">
    Update Users
    Set FiledCode = <cfqueryparam cfsqltype="cf_sql_varchar" value='#myrow[23]#'>
    Where User_Number = <cfqueryparam cfsqltype="cf_sql_integer" value='#myrow[1]#'>

    Update Table2
    Set something = <cfqueryparam cfsqltype="cf_sql_varchar" value='#myrow[23]#'>
    Where User_Number = <cfqueryparam cfsqltype="cf_sql_integer" value='#myrow[1]#'>
</cfquery> 

如果你想变得更复杂,你可以把这个循环分成几块,然后把它放在cfquery标签里面,这样它就可以包含100条左右的更新语句。

出于效率和安全原因,您应该进行的另一项改进是使用cfqueryparam。这将允许您的数据库引擎缓存查询计划,然后在随后的数万次调用中重用,并保护您免受 sql 注入。

【讨论】:

您回答的第二部分对我来说应该是简单的解决方法。但是第一部分最好将第二个更新放在同一个查询(UpdateRecords)中,这样只使用一个 cfquery 标签?或者第二部分,你说要把它们分成几块,你的意思是应该是什么样子?感谢您的帮助! 已编辑以在一个 cfquery 中演示多个更新。

以上是关于更新两个不同表中的字段的最有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

EF6 + SQL 14:将大量行上传到表中的最有效方法

将字符串字段值更改为其子字符串的最有效方法

此时确保 HBase 表中的行数增加的最有效方法是啥?

匹配 hive 数据库中两个字段的最有效方法

从sql列中拆分数据并将其保存在sql存储过程中的另一个表中的最有效方法是啥[重复]

检查表中是不是存在行的最有效方法是啥?