我有以下情况:我有一些CSV文件要导入Rails应用程序,数据集的大小可能超过100k行,这意味着使用大量内存 - 而我在服务器上没有这个内存。
每个CSV代表一个表转储。
现在,我的问题是我需要导入数据到几个表中,并通过外键维护关系。
到目前为止,我所做的大致如下:
- 创建ids缓存哈希 - 对于每个CSV /表,通过可能的属性
请查看此处的代码以获取更多详细信息。
注意:我需要的更多是
我已经尝试过一些优化:
看上面的例子,当我导入Lings和Properties时,它们将被分配不同的id,但我仍然希望LingsProperties与英语和法语相关联。 我不能在数据库中使用CSV id,它们是由另一个具有与我正在导入的应用程序不同模式的应用程序分配的。
更新2
我的Rails版本是3.0.20。 我正在升级到Rails 3.2(或更高版本),在那里我可以使用
每个CSV代表一个表转储。
现在,我的问题是我需要导入数据到几个表中,并通过外键维护关系。
到目前为止,我所做的大致如下:
- 创建ids缓存哈希 - 对于每个CSV /表,通过可能的属性
find_or_initialize
,或执行类似于model.where({complicated conditions}) || model.create({complicated conditions})
的操作来保存创建的对象
- 填充ids缓存映射CSV id
=> DB id
在complicated conditions
语句中,可以放置先前表中保存和缓存的某些ID。请查看此处的代码以获取更多详细信息。
注意:我需要的更多是
upsert
,而不仅仅是普通的insert
。我已经尝试过一些优化:
- 使用事务 => 使用更少的内存并快速插入
- 使用
crewait
gem => 比纯AR更快,但比事务慢 model.skip_callbacks(:create)
=> 速度提升或内存改进没有明显变化- 缓存了在所有其他表中广泛使用的
user
模型 => 高内存使用和较慢的速度(?) - 如果行已经存在,则只选择
id
属性以使用更少的内存 => 速度/内存没有大的区别 - 优化缓存的哈希结构:使用Google Hashes结构将ids存储为INT->INT => 使用更少10%的内存
- 单个且长的 SQL 查询: 这基本上是
crewait
的想法,但在我尝试过的范围内效果不佳。 activerecord-import
: 导入速度更快,但我将失去所有关系或 CSV 到数据库 ID 的映射。upsert
: 我看过它,但我想把它作为最后的选择(它有一点棘手,以我个人看来)。
欢迎任何建议、推荐,无论是工具、库、策略还是其他方面。
这是我拥有的 CSV 的简化示例:
lings.csv
------------------------
| id | name | depth |
------------------------
| 0 | English | 0 |
------------------------
| 1 | French | 0 |
------------------------
| etc.. |
------------------------
properties.csv
-----------------------------------
| id | name | description |
-----------------------------------
| 0 | Subject_Verb | bla, bla... |
-----------------------------------
| 1 | Verb_Subject | bla, bla... |
-----------------------------------
| etc.. |
-----------------------------------
lings_properties.csv
--------------------------------------
| id | value | ling_id | property_id |
--------------------------------------
| 0 | Yes | 0 | 0 |
--------------------------------------
| 1 | No | 1 | 1 |
--------------------------------------
| etc.. |
--------------------------------------
看上面的例子,当我导入Lings和Properties时,它们将被分配不同的id,但我仍然希望LingsProperties与英语和法语相关联。 我不能在数据库中使用CSV id,它们是由另一个具有与我正在导入的应用程序不同模式的应用程序分配的。
更新2
我的Rails版本是3.0.20。 我正在升级到Rails 3.2(或更高版本),在那里我可以使用
first_or_create
(或类似)但目前我被困在Rails 3.0。
foreign_keys
不是已经在表中了吗?如果是的话,那么你只需要类似于LOAD DATA INFILE 'path/to/file.csv' INTO TABLE your_table FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'
这样在MySQL
中操作,然后为了节省内存,直接使用File.open
读取文件并自己解析 csv,相比使用 ruby 的CSV
库会节省很多内存。 - bjhaidMySQL
提示符,那么我将使用auto_increment
设置ID:这样一来,我不会失去所有关系吗? - MarcoL