【发布时间】: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),这会导致每行有很多额外的查询。当我为每个价格计算哈希时,我仍然需要查询我的“报价”表并为每一列发送大量查询以找出发生了什么变化。
标签: php mysql import bigdata rdbms