我正在寻找在SQL中实现大数据更新/插入的最佳方法。我的具体情况是使用MySQL 5.6,但理论上SQL的版本并不是那么重要。
我正在下载一个大型CSV文件,其中包含我需要转储到MySQL表中的数据。我的应用程序解析CSV并准备插入数据库。
我需要将表格作为每次进来的数据(CSV)的精确副本,而不是每次都添加到最后。我正在寻找实现这一目标的最佳方式。
对于我目前的SQL功能,我认为最好每次都简单地截断表并在数据填充时填充它,但我现在不确定这是否比索引列并使用{{{}更好。 1}}。
我的问题如下:
最好截断然后在空表上插入数据,或者更好地查找数据差异,并使用INSERT ... ON DUPLICATE KEY
仅更新应用程序发现数据差异的行
在此之后的任何一种方式,最好是为每行数据格式化单个SQL INSERT .. ON DUPLICATE KEY
/ UPDATE
查询并将它们发送到服务器。或者更好地格式化包含所有数据的非常大的查询,或者可能将更大的查询拆分成更易于管理的内容,以免服务器超时。
表中大约有10万行正在通过。目前,我在运行任何INSERT之前截断表。然后,我将行拆分为10个不同的集合,并对数据库运行10个大INSERT
个查询。我唯一担心的是我对表锁定知之甚少,并且不确定拆分它们是否真正实现了重要性。
我在这里问的原因是因为我的显示器中的数据库使用情况图显示出峰值,我想也许更好的是拥有更稳定的数据流并试图找出如何实现这一目标。
据我所知,这只是磁盘写入,但所有图形看起来或多或少都相同,有很多尖峰,没有一致性。
答案 0 :(得分:1)
在处理大型csv
文件时,应使用LOAD DATA LOCAL INFILE
而不是插入/更新操作。您没有提到在插入之前执行的解析操作,其中一些可能仅使用LOAD DATA LOCAL INFILE
。 TRUNCATE
声明前的表格。
以下是LOAD DATA LOCAL INFILE
语句的示例,该语句忽略第一行(标题)并在加载数据时替换价格字段的逗号值,仅作为示例:
LOAD DATA LOCAL INFILE 'file.csv'
INTO TABLE table
CHARACTER SET UTF8
FIELDS TERMINATED BY '\t'
ENCLOSED BY '\"'
IGNORE 1 LINES
(col1,col2,col3,colN, @price)
SET price = REPLACE(@price,',','.');
正如您所说,您需要csv中的所有字段,只需在此处传递列的名称
(col1,col2,col3,colN, @price)
与csv中的顺序相同。这将比您可以编写的任何插入语句更快。
要启用LOAD DATA LOCAL INFILE
,您需要在建立与数据库的连接时设置连接标记(直接在连接选项中的选项中,它之后不起作用),例如,使用php PDO:
$dbh = new PDO('mysql:host=' . env('DB_HOST') . ';dbname=' . $database, env('DB_USERNAME'), env('DB_PASSWORD'),
[PDO::MYSQL_ATTR_LOCAL_INFILE => 1]);