mysql中定价表中数据的巨大连续(重新)导入和刷新

Posted

技术标签:

【中文标题】mysql中定价表中数据的巨大连续(重新)导入和刷新【英文标题】:Huge continous (re)import and refresh of data in pricing table in mysql 【发布时间】:2020-01-27 23:32:22 【问题描述】:

我有一个大型数据集(约 250 万行),需要将其连续(重新)导入到 mysql 表“price_list”中。所有表都是 InnoDB。目前我正在使用“LOAD DATA LOCAL INFILE”,因为这些数据集来自 csv 文件:

LOAD DATA LOCAL INFILE 'sample.csv'
INTO TABLE `price_list`
(...)
(...)
IGNORE 1 LINES

db "price_list" 中的表示例:

hotel_id | room_category            | price 1 person | price 2nd person     | <other meta info>

1        | single room (w/o window) | 150€           | 200€                 | ...
2        | single room (w window)   | 170€           | 220€                 | ...
3        | single room (rooftop)    | 240€           | 250€                 | ...
4        | single room (whirlpool)  | 200€           | 280€                 | ...
5        | double room (w/o window) | 200€           | 220€                 | ...
6        | double room (w window)   | 240€           | 260€                 | ...
7        | double room (rooftop)    | 280€           | 300€                 | ...
8        | double room (whirlpool)  | 320€           | 340€                 | ...
(...)

根据这些数据,我需要更新表“offers”(该表位于另一个数据库中,“price_list”的用户无法访问“offers”,并且在技术上无法提供正确的访问权限)并更新定价。价格变化很大,我们需要每 15 分钟重新导入这些数据。

id  |       offer_name           |   price_single_room    |    price_double_room
1   |  WHIRLPOOL OFFER SINGLES   |         200€           |          200€

在上面的示例中,选择了“最佳”单人间(带漩涡浴缸)的价格(200 欧元)。此报价中不需要第二个价格,而是故意计算的(如果需要,可以停用)。

我目前的解决方案是我从 php 中的“offers”表中获取所有报价,这些报价被标记为活动,并循环遍历它们 (oof)。每个优惠有 6 列不同的价格(例如酒店有不同的房间可供选择;第 1 列是单人间的最优惠价格,第 2 列是双人间的最优惠价格,...)需要查找。

目前我们有大约 10.000 个有效报价,这意味着我将以下数量发送到数据库服务器:10.000 个查询 * 6 个查询以查找每个报价的最佳价格。

当我在同一台服务器上执行这些查询(没有网络延迟等)时,性能并不是最差的(整个工作大约需要 5 分钟(导入约 250 万行,刷新定价,...)),但是由于数据在增长,我们想拆分数据库和网络服务器。我现在意识到,我刷新价格的部分会产生大量网络开销,而且速度非常慢,因为从网络服务器到数据库服务器的每个请求大约需要 0.025 秒(仅刷新价格需要 25 分钟)。

我想到了以下解决方案:

将表“offers”移动到同一个数据库“price_list”= 工作,但仍然很慢,因为数据库服务器与 Web 服务器不在同一台机器上 = 网络延迟是瓶颈。

编写一个由 PHP 触发的存储过程,由数据库服务器完成。

是否有人对这些重复性数据加载有经验,并且可能为我的给定问题提供解决方案?目标是减少时间并拆分 Web 和数据库服务器。

谢谢!

【问题讨论】:

听起来您需要创建一个更适合您查询的架构,并在导入期间或之后将原始导入格式转换为该架构。一个有效的技巧是暂存一个新表(例如offers__updated),将数据加载到其中,进行任何清理,然后交换:RENAME TABLE offers TO offers__old, offers__updated TO offers 意味着没有长表锁。 嗨@tadman,感谢您的回复。目前我已经在使用“price_list”表进行此操作;我有两个保存相同表的数据库;一个是“实时”/“活动”数据库,一个是“临时”/“非活动”数据库。 cronjob 仅在非活动数据库内工作(防止锁定活动数据库)。完成时:将活动数据库的状态切换为非活动状态,并从非活动状态切换为活动数据库。我认为这对更高的网络延迟没有帮助。在我的情况下,它只需要 25 分钟刷新)。我的“price_list”表是所有可用价格的来源。 通常情况下,您可以快速从服务器获取数据,因此如果您可以将内容转储为 CSV,计算需要更新的行,然后单独更新这些行,您可能会获得更好的性能.我已经使用散列完成了这项工作,因为每一行都有一个 SHA2-256 其 CSV 行内容的散列,并且只有数据已更改的行(例如,在数据库中找不到计算的散列)才会被插入。就像SELECT row_hash FROM tablename 和一系列REPLACE INTO 操作一样简单。 您可以在一分钟内计算出 2.5MM 行文件的哈希/差异。如果您认为这会有所帮助,您甚至可以将该文件分块并在多个线程上运行这些哈希。 @tadman 我用表格外观的适当示例更新了我的问题。导入 csv 数据大约需要 1 分钟,这并不是什么大问题。在我看来,问题是我需要在“price_list”中查找“price_single_room”、“price_double_room”(以及其他列,如 price_suite_room),这会导致每行有很多额外的查询。当我为每个价格计算哈希时,我仍然需要查询我的“报价”表并为每一列发送大量查询以找出发生了什么变化。 【参考方案1】:

您有一个名为 `real; 的表。以下将用包含新数据的新表替换它。

CREATE TABLE t_new LIKE real;
LOAD DATA INFILE new ...;
RENAME TABLE real TO t_old,
             t_new TO real;
DROP TABLE t_old;

注意事项:

⚈  The LOAD DATA step can be replaced by whatever process you have for importing the data.
⚈  The Loading is the only slow step.
⚈  The RENAME is atomic, so real always exists.
⚈  You may choose to delay the DROP in case the new data might be bad and you want to revert.
⚈  FOREIGN KEYs can be a hassle; it might be good not to have such.

-- http://mysql.rjweb.org/doc.php/deletebig#optimal_reload_of_a_table

【讨论】:

嗨 Rick,我已经用“LOAD DATA”刷新了“price_list”表,而且速度非常快。 Imo 问题出在“报价”表上,当我在同一台机器上更新表格时,更新“报价”中价格的整个过程大约需要 2-3 分钟,而如果它在远程机器上则需要(现在经过多次性能调整)大约 13 分钟,在 65 分钟之前。问题实际上是我需要对远程表进行多次查询(在表“price_list”中找到优惠 XYZ 的最佳价格)......实际上我正在考虑像急切加载这样的事情。

以上是关于mysql中定价表中数据的巨大连续(重新)导入和刷新的主要内容,如果未能解决你的问题,请参考以下文章

怎么把mssql改为mysql

MySQL——导入数据报字段编码错误

mysql文件导入现有数据库表中

怎么往mysql数据库的表中批量导入数据

22.把hive表中数据导入到mysql中

mysql中把一个表的数据批量导入另一个表中(不同情况)