我需要在mySQL数据库中将一个巨大的CSV文件插入到2个具有1:n关系的表中.
CSV文件每周发送一次,大约1GB,需要附加到现有数据.其中每个表都有一个自动增量主键.
我试过了:
还有什么建议?
让我们说简化这是我的数据结构:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<string> Codes { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我需要从csv插入到这个数据库中:
User (1-n) Code
+---+-----+-----+ +---+---+-----+
|PID|FName|LName| |CID|PID|Code |
+---+-----+-----+ +---+---+-----+
| 1 |Jon | Foo | | 1 | 1 | ed3 |
| 2 |Max | Foo | | 2 | 1 | wst |
| 3 |Paul | Foo | | 3 | 2 | xsd |
+---+-----+-----+ +---+---+-----+
Run Code Online (Sandbox Code Playgroud)
这是CSV文件的示例行
Jon;Foo;ed3,wst
Run Code Online (Sandbox Code Playgroud)
LOAD DATA LOCAL INFILE由于我的写作权限受到限制,因此无法进行批量加载
参考你的答案我会替换
using (MySqlCommand myCmdNested = new MySqlCommand(cCommand, mConnection))
{
foreach (string Code in item.Codes)
{
myCmdNested.Parameters.Add(new MySqlParameter("@UserID", UID));
myCmdNested.Parameters.Add(new MySqlParameter("@Code", Code));
myCmdNested.ExecuteNonQuery();
}
}
Run Code Online (Sandbox Code Playgroud)
同
List<string> lCodes = new List<string>();
foreach (string code in item.Codes)
{
lCodes.Add(String.Format("('{0}','{1}')", UID, MySqlHelper.EscapeString(code)));
}
string cCommand = "INSERT INTO Code (UserID, Code) VALUES " + string.Join(",", lCodes);
using (MySqlCommand myCmdNested = new MySqlCommand(cCommand, mConnection))
{
myCmdNested.ExecuteNonQuery();
}
Run Code Online (Sandbox Code Playgroud)
生成一个插入语句而不是 item.Count
考虑到数据量很大,最好的方法(性能方面)是将尽可能多的数据处理留给数据库而不是应用程序。
创建一个临时表,用于临时保存 .csv 文件中的数据。
CREATE TABLE `imported` (
`id` int(11) NOT NULL,
`firstname` varchar(45) DEFAULT NULL,
`lastname` varchar(45) DEFAULT NULL,
`codes` varchar(450) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)
将数据从表加载.csv到该表中非常简单。我建议使用MySqlCommand(这也是您当前的方法)。此外,对所有语句使用相同的对象 将减少总执行时间MySqlConnectionINSERT。
然后,为了进一步处理数据,您可以创建一个存储过程来处理它。
假设这两个表(取自您的简化示例):
CREATE TABLE `users` (
`PID` int(11) NOT NULL AUTO_INCREMENT,
`FName` varchar(45) DEFAULT NULL,
`LName` varchar(45) DEFAULT NULL,
PRIMARY KEY (`PID`)
) ENGINE=InnoDB AUTO_INCREMENT=3737 DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)
和
CREATE TABLE `codes` (
`CID` int(11) NOT NULL AUTO_INCREMENT,
`PID` int(11) DEFAULT NULL,
`code` varchar(45) DEFAULT NULL,
PRIMARY KEY (`CID`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)
您可以拥有以下存储过程。
CREATE DEFINER=`root`@`localhost` PROCEDURE `import_data`()
BEGIN
DECLARE fname VARCHAR(255);
DECLARE lname VARCHAR(255);
DECLARE codesstr VARCHAR(255);
DECLARE splitted_value VARCHAR(255);
DECLARE done INT DEFAULT 0;
DECLARE newid INT DEFAULT 0;
DECLARE occurance INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE cur CURSOR FOR SELECT firstname,lastname,codes FROM imported;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
import_loop:
LOOP FETCH cur INTO fname, lname, codesstr;
IF done = 1 THEN
LEAVE import_loop;
END IF;
INSERT INTO users (FName,LName) VALUES (fname, lname);
SET newid = LAST_INSERT_ID();
SET i=1;
SET occurance = (SELECT LENGTH(codesstr) - LENGTH(REPLACE(codesstr, ',', '')) + 1);
WHILE i <= occurance DO
SET splitted_value =
(SELECT REPLACE(SUBSTRING(SUBSTRING_INDEX(codesstr, ',', i),
LENGTH(SUBSTRING_INDEX(codesstr, ',', i - 1)) + 1), ',', ''));
INSERT INTO codes (PID, code) VALUES (newid, splitted_value);
SET i = i + 1;
END WHILE;
END LOOP;
CLOSE cur;
END
Run Code Online (Sandbox Code Playgroud)
对于源数据中的每一行,它都会INSERT为user表创建一个语句。然后有一个WHILE循环来分割逗号分隔的代码,并为每个代码创建一个INSERT语句codes。
关于 的使用LAST_INSERT_ID(),它在每个连接的基础上都是可靠的(请参阅此处的文档)。如果用于运行此存储过程的MySQL连接没有被其他事务使用,则使用LAST_INSERT_ID()是安全的。
生成的 ID 按每个连接保存在服务器中。这意味着该函数返回给给定客户端的值是为该客户端影响 AUTO_INCRMENT 列的最新语句生成的第一个 AUTO_INCRMENT 值。该值不会受到其他客户端的影响,即使它们生成自己的 AUTO_INCRMENT 值。此行为确保每个客户端都可以检索自己的 ID,而无需关心其他客户端的活动,也不需要锁或事务。
编辑:这是省略了 temp-table 的 OP 变体imported。您无需将 .csv 中的数据插入到表中imported,而是调用 SP 将它们直接存储到数据库中。
CREATE DEFINER=`root`@`localhost` PROCEDURE `import_data`(IN fname VARCHAR(255), IN lname VARCHAR(255),IN codesstr VARCHAR(255))
BEGIN
DECLARE splitted_value VARCHAR(255);
DECLARE done INT DEFAULT 0;
DECLARE newid INT DEFAULT 0;
DECLARE occurance INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
INSERT INTO users (FName,LName) VALUES (fname, lname);
SET newid = LAST_INSERT_ID();
SET i=1;
SET occurance = (SELECT LENGTH(codesstr) - LENGTH(REPLACE(codesstr, ',', '')) + 1);
WHILE i <= occurance DO
SET splitted_value =
(SELECT REPLACE(SUBSTRING(SUBSTRING_INDEX(codesstr, ',', i),
LENGTH(SUBSTRING_INDEX(codesstr, ',', i - 1)) + 1), ',', ''));
INSERT INTO codes (PID, code) VALUES (newid, splitted_value);
SET i = i + 1;
END WHILE;
END
Run Code Online (Sandbox Code Playgroud)
注意:分割代码的代码取自这里(MySQL不提供字符串分割功能)。
| 归档时间: |
|
| 查看次数: |
3227 次 |
| 最近记录: |