将关系检查和可能的不良数据逐行插入大量数据
我已经阅读了许多与此相似的文章和问题,但是已经发现了足够近的东西。
我在10列excel文件中有40,000行。 这里的数据是由纸张手工input的。
在我需要首先检查的文件中有两个主要的数字MO&Order。 由于这些是手工input,他们可能是错的。
我有2张桌子MO表
moID MO Order 3409 87234 23845 3410 84562 21342 etc... (38k rows)
和
printID moID user date printer 5 3409 Brad 01/24 printer1 34 3409 Brad 01/30 printer1 40 3410 Joe 01/31 printer1 etc... (9k ish and growing)
处理:
我遍历每一行在我的C#应用程序,查询获取moID。 然后查询该作业是否已经存在,然后执行Insert。 如果无法findmoID,我查询logging可能的MO和顺序组合,以便稍后修复文件。
LINK QUERYS:
curMOID = dbReports.MoNumbers.Where(r => r.moNumber == moNum && r.moOrder == orderNum).Select(c => c.id_moNumber).FirstOrDefault(); var printJobs = dbReports.PaperPrints.Where(q => q.id_moNumber == curMOID && q.printDate == printDate && q.rowExcelFile == curRow); if (printJobs.Where(q => q.printSize == null).Count() == 0)
题:
我的moID查询需要〜250ms(申请时间,直接查询是〜0.075ms)。 与已经存在的和选项列表一样。 所以每一行都需要大约0.5秒才能完成。 在4万行是花5个多小时。 我必须每天与用户做这个。 有没有更好的方法来做到这一点或通过应用程序来加快查询速度。
是的,这是一个痛苦的,非常痛苦的做法。 有一个无痛的方式,更快,不涉及任何编码。
步骤1:将文件导出为CSV
第二步:使用LOAD DATA INFILE
使用它将数据加载到一个虚拟表中
LOAD DATA INFILE语句以非常高的速度从文本文件中读取行到表中
第3步:创build目标表
使它完全像虚拟表,但要确保你有不重复的列上的唯一索引。
你可以用CREATE TABLE LIKE语句来做到这一点
第4步:从温度select最终
是的,语法是
INSERT IGNORE INTO destination SELECT * FROM tmp_table
第5步:使用多表删除来清理tmp_table
在那里你有一个无法导入行的表。 而且你用一行代码在一分钟内完成了
除非我错误地将你使用的moID
作为唯一键来确定你是否应该插入,所以:
你最好的select是开始批量查询。
取5000个moID
并先查询它们,然后删除所有从5000退出的文件,然后执行剩余的批量插入操作。 冲洗并重复。
谢谢@ e4c5。 有我需要去的地方 想给我一个清晰的画面,我做了什么。 这曾经花了5 + HOURS,现在需要5秒。 我仍然使用C#程序来检查文件,创buildcsv并通过LOAD DATA INFILE发送它。
1) 创build一个CSV,每行包含所有表的信息。
- 使用EPPLUS打开文件。 检查我想要的types的必填字段,如果出现错误,请停止,以便用户修复必填字段。
2) 创build了我想要插入的表的副本
- 新表被称为StagePrintJob
3) 在我的情况下添加了MO和Order的值。
4) 将舞台表上的moID字段更改为默认值0
5) 使用LOAD DATA INFILE查询
-
我截断(清除)表,所以我不必每次创build它。 只是重用。
"TRUNCATE TABLE `" + table + "`; " + string.Format("LOAD DATA LOCAL INFILE '{0}' INTO TABLE `" + table + "` ", csvFullName).Replace(@"\", @"\\") + "FIELDS TERMINATED BY ',' " + "ENCLOSED BY '\"' " + "LINES TERMINATED BY '\\r\\n' " + "ignore 1 lines " + "(@printFix, moClient, moNumber, moOrder, printComment, printPrinter, printStatus, printUser, printIssue, printSolution, printQty, rowExcelFile, excelFile) " + "SET printDate = STR_TO_DATE(@printFix, '%m/%d/%Y'); " + "Call PaperPrintProcedure('" + printFileName + "')";
-
SET printDate是一种将我的datestring转换为mySQL可以理解的datestring的方法
- 我在LOAD DATA LOCAL INFILE上使用了LOCAL,所以我可以在本地PC上使用一个文件,而不必先将它发送到mySQL服务器。
6) 创build一个存储过程(可以只运行命令)。 我做了一个更新查询检查我的价值对我想要的表。
update StagePrint test inner join MoNumbers mo on test.moNumber = mo.moNumber && test.moOrder = mo.moOrder set test.id_moNumber = mo.id_moNumber;
7) 我插入到我的实际表中的阶段行,只要它现在有一个MO的ID。
-
我删除了与我的文件相同的行,因为在excel文件中没有好的ID,所以现在可以使用。
DELETE FROM `PaperPrint` WHERE `excelFile` = printFileName; insert into PaperPrint(id_moNumber, printQty, printDate, printSize, printUser, printPrinter, printStatus, printIssue, printSolution, printComment, rowExcelFile, excelFile) select id_moNumber, printQty, printDate, printSize, printUser, printPrinter, printStatus, printIssue, printSolution, printComment, rowExcelFile, excelFile from StagePrint where StagePrint.id_moNumber <> 0;
8) 在StagedTable中查询ID = 0
任何logging,并修复或删除它们。