将批量数据插入Postgres

时间:2015-07-12 16:16:15

标签: python sql-server database entity-framework postgresql

我遇到了将数百行数据插入关系数据库(PostgreSQL)的问题。要插入的数据保存在.csv文件中,数据将插入到具有各种关系(一对一,一对多,多对多)的多个表中。大约有10多个表,其中包含许多关联实体。

假设表A和表B具有多对多关系,因此表AB(关联实体)。在插入期间,有必要在将数据插入表A和表B之后,将插入的主键映射到关联实体表AB中。

更具体地说,以下代码显示了我的一些数据库表是如何相关的(所有表都是使用Django模型创建的):

class Restaurant(models.Model):
    ... 
    promotion = models.ForeignKey(Promotion)
    menus = models.ManyToManyField(Menu)

class Menu(models.Model):
    ...
    mains = models.ManyToManyField(Main)
    drinks = models.ManyToManyField(Drinks)
    desserts = models.ManyToManyField(Dessert)

注意:有10多个表以与上面所示类似的方式相互关联

.csv文件数据如下所示,需要不正确的数据检查。例如:

no, restaurant name, restaurant description, restaurant type, restaurant homepage, restaurant country, restaurant age, restaurant awards, restaurant promotions, restaurant drinks, restaurant desserts, restaurant mains
1, Papa Delicious, This restaurant is ......, Italian, www.papadelicious.com, United States, 3, , , [Orange Juice, Apple Juice, Coffee], [Ice-cream], [Linguine, Some Burger]

在插入数据库时​​,不应将任何重复的菜肴或饮料作为新行插入,而是更新相应关联实体中的键。

这些数据每周会被插入几次,每行不应超过1分钟,因为错误检查已经花费了一些时间,插入可能由多个用户在一个点上执行时间。 但是,数百行数据将是一次性插入(大约要插入600 ++行数据)

我正在寻找将数据插入所有相应的表格的有效方法。我已经查看了COPY,但我真的不知道如何同时复制到多个表并分别映射外键。

我还尝试编写自己的脚本将数据插入.py文件中,但逐行插入效率非常低,尤其是当我插入多个表并映射外键时在关联实体中。

我想编写一个脚本来进行检查和插入是解决这个问题的最佳方法,但是在处理大量数据和10多个实体时,逐行进行检查和所有外键映射都会非常低效。

那里有更好的解决方案吗?

2 个答案:

答案 0 :(得分:1)

PostgreSQL最初如何最好地填充数据库有guide,他们建议使用COPY命令批量加载行。该指南还提供了一些关于如何加快进程的其他好技巧,比如在加载数据之前删除索引和外键(并在之后添加它们)。

此外,this是对这种情况的精心解答。请检查一下。

答案 1 :(得分:0)

在您的代码运行后计算出您的速度要求。 我怀疑你会以低于10 /秒的速度插入行 600行=最多2-3分钟

  1. 找出表之间的依赖关系。独立表(w.o.FKs)先行。

  2. 每张桌子。

    ex:  Restaurant (needs to go after Menus and Promotions)
    
    rest = Restaurant()  (or select for update if it exists already)
    
    - map CSV cell data to direct model fieldnames.
    
        rest.name = csv.restaurant name
        rest.age = csv.age
    
    - if a FK field
        get corresponding model by search (on name/label I assume)
        assign to model field
    
        rest.promotion = Promotion.objects.get(name=csv.promotion)
    
        you need to be catch missing lookups, report on it and proceed
        to the next row.  
    
        One flaw I foresee is that everything you have
        seems centred around 'identification by name'.  Drinks.objects.get(name="orange juice")
        What if you change the label or inconsistent?  What if a restaurant name changes?
    
        Or is the first "no=1" column is meant to address in the restaurant CSV a consistent key?
    
    -   save model
        rest.save()
    
    - if MTM field
        - lookup corresponding model by search 
        - push values onto an array
    
        li_menu = []
        for menu_name in csv.menu:
            menumtm = MenuMTM()
            menumtm.menu = Menus.objects.get(name=menu_name)
            menumtm.restaurant = rest
            menumtm.save()
    
    if you DO need to optimize, you can pre-load commonly referred tables
    so that you can skip "costly" Model.objects.get(name=name).  Probably
    not worth the trouble.