我正在寻找在 SQL 中实现大数据更新/插入的最佳方法。我的特殊情况是使用 MySQL 5.6,但理论上 SQL 的版本并不那么重要。
我正在下载一个大型 CSV 文件,其中包含我需要转储到 MySQL 表中的数据。我的应用程序解析 CSV 并准备插入数据库。
我需要表格是每次传入的数据 (CSV) 的精确副本,而不是每次都添加到末尾。我正在寻找实现这一目标的最佳方法。
对于我目前的 SQL 能力,我认为最好每次都截断表并在数据通过时用数据填充它,但我现在不确定这是否比索引列和使用 插入 ... 在重复键上
。
我的问题如下:
最好是截断然后将数据插入空表,还是更好地找出数据差异并使用
INSERT .. ON DUPLICATE KEY
仅更新应用程序发现数据差异在此之后的任何一种方式,是否最好为每行数据格式化单独的 SQL
UPDATE
/INSERT
查询并将它们发送到服务器。或者最好是格式化一个包含所有数据的非常大的查询,或者可能将该较大的查询拆分为更易于管理的内容,以免让服务器超时。
正在处理的表中大约有 10 万行。目前,我在运行任何 INSERT 之前截断表。然后,我将这些行分成 10 个不同的集合,并对数据库运行 10 个大型 INSERT
查询。我唯一担心的是,我对表锁定了解不够,并且不确定拆分这些表是否真的有任何重要意义。
我在这里问这个问题的原因是因为我的监视器中的数据库使用情况图表显示峰值,我认为拥有更稳定的数据流可能会更好,并且我正在尝试弄清楚如何实现这一点。
我知道这只是磁盘写入,但所有图表看起来或多或少都一样,有很多尖峰且不一致。
最佳答案
你应该使用 LOAD DATA LOCAL INFILE
当您处理大型 csv
文件时,而不是插入/更新操作。您没有提到在插入之前执行的解析操作,其中一些操作可能仅使用 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]);
关于mysql - 寻找最佳实践/最高效的大型 SQL UPDATE/INSERT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32303552/