แทรกจำนวนมากด้วย SQLAlchemy ORM


131

มีวิธีใดบ้างที่จะทำให้ SQLAlchemy ทำการแทรกจำนวนมากแทนที่จะแทรกแต่ละออบเจ็กต์ กล่าวคือ

ทำ:

INSERT INTO `foo` (`bar`) VALUES (1), (2), (3)

ค่อนข้างมากกว่า:

INSERT INTO `foo` (`bar`) VALUES (1)
INSERT INTO `foo` (`bar`) VALUES (2)
INSERT INTO `foo` (`bar`) VALUES (3)

ฉันเพิ่งแปลงรหัสบางส่วนเพื่อใช้ sqlalchemy แทนที่จะเป็น raw sql และแม้ว่าตอนนี้จะทำงานได้ดีกว่ามาก แต่ดูเหมือนว่าจะช้าลงในตอนนี้ (มากถึง 10 ตัว) ฉันสงสัยว่านี่เป็นเหตุผลหรือไม่

ฉันสามารถปรับปรุงสถานการณ์โดยใช้เซสชันได้อย่างมีประสิทธิภาพมากขึ้น ในขณะนี้ฉันมีautoCommit=Falseและทำsession.commit()หลังจากที่ฉันได้เพิ่มบางสิ่งแล้ว แม้ว่าสิ่งนี้ดูเหมือนจะทำให้ข้อมูลค้างหาก DB ถูกเปลี่ยนไปที่อื่นเช่นแม้ว่าฉันจะทำการสืบค้นใหม่ฉันยังคงได้ผลลัพธ์เก่ากลับมา?

ขอบคุณสำหรับความช่วยเหลือของคุณ!


1
สิ่งนี้อาจช่วยได้: stackoverflow.com/questions/270879/…
Sean Vieira

1
Nick ฉันเข้าใจว่านี่เป็นโพสต์เก่ามาก เป็นไปได้ไหมที่จะอัปเดตชื่อเรื่องให้ถูกต้องเช่น "หลายระเบียนแทรกด้วย SQLAlchemy ORM" คำสั่งแทรกหลายระเบียนเช่นเดียวกับที่คุณระบุค่อนข้างแตกต่างจากการดำเนินการโหลดจำนวนมากในระดับฐานข้อมูล การแทรกจำนวนมากมีไว้สำหรับการอัปโหลดข้อมูลมากกว่า 1,000 รายการโดยปกติจะมาจากชุดข้อมูลขนาดใหญ่และดำเนินการโดยผู้จัดการแอปพลิเคชันไม่ใช่การดำเนินการ REST หรือโค้ดระดับแอปพลิเคชัน .... มาใช้ระบบการตั้งชื่อของเราให้เหมาะสมกันเถอะ
W4t3randWind

สำหรับผู้ที่สะดุดเมื่อคำถามนี้ในขณะที่มองหาข้อมูลเกี่ยวกับการดำเนินงานจำนวนมากใน sqlalchemy หลัก (ไม่ออม) ดูคำตอบของฉันคำถามอื่น
Nickolay

คำตอบ:


174

SQLAlchemy เปิดตัวในเวอร์ชัน1.0.0:

การดำเนินการจำนวนมาก - เอกสาร SQLAlchemy

ด้วยการดำเนินการเหล่านี้คุณสามารถทำการแทรกหรืออัปเดตจำนวนมากได้แล้ว!

ตัวอย่างเช่นคุณสามารถทำได้:

s = Session()
objects = [
    User(name="u1"),
    User(name="u2"),
    User(name="u3")
]
s.bulk_save_objects(objects)
s.commit()

ที่นี่จะมีการแทรกจำนวนมาก


30
คุณต้องใช้ s.commit () ในการบันทึกจริง (ฉันต้องใช้เวลาเล็กน้อยในการคิดออก)
horcle_buzz

3
ฉันลองสิ่งนี้ด้วย sqlachemy 1.0.11 และมันยังสร้างคำสั่งแทรก 3 แต่มันเร็วกว่าการทำงานของ orm ปกติมาก
zidarsk8

3
แม้ว่าจะไม่เกี่ยวข้องกับคำถาม OPs แต่ก็คุ้มค่าที่จะกล่าวถึงสิ่งนี้จะทำลายคุณสมบัติบางอย่างของ ORM docs.sqlalchemy.org/th/rel_1_0/orm/…
dangel

@dangel ใช่ขอบคุณสำหรับการโพสต์สิ่งนี้ แม้ว่าหัวข้อของ OP จะเกี่ยวข้องกับ "การโหลดจำนวนมาก" คำถามของเขาเกี่ยวกับข้อความแทรกหลายระเบียนไม่มีส่วนเกี่ยวข้องกับคุณลักษณะการโหลดจำนวนมากของ sqlalchemy
W4t3randWind

เมื่อเทียบกับการแทรกข้อมูลเดียวกันจาก CSV กับ\copypsql (จากไคลเอนต์เดียวกันไปยังเซิร์ฟเวอร์เดียวกัน) ฉันเห็นความแตกต่างอย่างมากในด้านประสิทธิภาพในฝั่งเซิร์ฟเวอร์ซึ่งส่งผลให้มีการแทรกเพิ่มขึ้นประมาณ 10 เท่า เห็นได้ชัดว่าเป็นการโหลดจำนวนมากโดยใช้\copy(หรือCOPYบนเซิร์ฟเวอร์) โดยใช้การบรรจุในการสื่อสารจากไคลเอนต์ไปยังเซิร์ฟเวอร์เป็นจำนวนมากดีกว่าการใช้ SQL ผ่าน SQLAlchemy ข้อมูลเพิ่มเติม: กลุ่มขนาดใหญ่แทรกประสิทธิภาพแตกต่าง PostgreSQL VS ...
gertvdijk

41

เอกสาร sqlalchemy มีการเขียนเกี่ยวกับประสิทธิภาพของเทคนิคต่างๆที่สามารถใช้สำหรับการแทรกจำนวนมาก:

โดยทั่วไปแล้ว ORM ไม่ได้มีไว้สำหรับการแทรกจำนวนมากที่มีประสิทธิภาพสูง - นี่คือเหตุผลทั้งหมดที่ SQLAlchemy เสนอ Core นอกเหนือจาก ORM เป็นส่วนประกอบชั้นหนึ่ง

สำหรับกรณีการใช้งานของการแทรกจำนวนมากอย่างรวดเร็วการสร้าง SQL และระบบการดำเนินการที่ ORM สร้างขึ้นด้านบนเป็นส่วนหนึ่งของ Core เมื่อใช้ระบบนี้โดยตรงเราสามารถสร้าง INSERT ที่แข่งขันได้โดยใช้ API ฐานข้อมูลดิบโดยตรง

หรืออีกวิธีหนึ่ง SQLAlchemy ORM นำเสนอชุดวิธีการดำเนินการจำนวนมากซึ่งจัดเตรียม hooks ไว้ในส่วนย่อยของหน่วยของกระบวนการทำงานเพื่อที่จะปล่อยโครงสร้าง INSERT และ UPDATE ระดับแกนกลางด้วยระบบอัตโนมัติแบบ ORM ในระดับเล็กน้อย

ตัวอย่างด้านล่างนี้แสดงให้เห็นถึงการทดสอบตามเวลาสำหรับวิธีการต่างๆในการแทรกแถวโดยเริ่มจากแบบอัตโนมัติที่สุดไปหาน้อยที่สุด ด้วย cPython 2.7 เวลาทำงานที่สังเกตได้:

classics-MacBook-Pro:sqlalchemy classic$ python test.py
SQLAlchemy ORM: Total time for 100000 records 12.0471920967 secs
SQLAlchemy ORM pk given: Total time for 100000 records 7.06283402443 secs
SQLAlchemy ORM bulk_save_objects(): Total time for 100000 records 0.856323003769 secs
SQLAlchemy Core: Total time for 100000 records 0.485800027847 secs
sqlite3: Total time for 100000 records 0.487842082977 sec

สคริปต์:

import time
import sqlite3

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String,  create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

Base = declarative_base()
DBSession = scoped_session(sessionmaker())
engine = None


class Customer(Base):
    __tablename__ = "customer"
    id = Column(Integer, primary_key=True)
    name = Column(String(255))


def init_sqlalchemy(dbname='sqlite:///sqlalchemy.db'):
    global engine
    engine = create_engine(dbname, echo=False)
    DBSession.remove()
    DBSession.configure(bind=engine, autoflush=False, expire_on_commit=False)
    Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)


def test_sqlalchemy_orm(n=100000):
    init_sqlalchemy()
    t0 = time.time()
    for i in xrange(n):
        customer = Customer()
        customer.name = 'NAME ' + str(i)
        DBSession.add(customer)
        if i % 1000 == 0:
            DBSession.flush()
    DBSession.commit()
    print(
        "SQLAlchemy ORM: Total time for " + str(n) +
        " records " + str(time.time() - t0) + " secs")


def test_sqlalchemy_orm_pk_given(n=100000):
    init_sqlalchemy()
    t0 = time.time()
    for i in xrange(n):
        customer = Customer(id=i+1, name="NAME " + str(i))
        DBSession.add(customer)
        if i % 1000 == 0:
            DBSession.flush()
    DBSession.commit()
    print(
        "SQLAlchemy ORM pk given: Total time for " + str(n) +
        " records " + str(time.time() - t0) + " secs")


def test_sqlalchemy_orm_bulk_insert(n=100000):
    init_sqlalchemy()
    t0 = time.time()
    n1 = n
    while n1 > 0:
        n1 = n1 - 10000
        DBSession.bulk_insert_mappings(
            Customer,
            [
                dict(name="NAME " + str(i))
                for i in xrange(min(10000, n1))
            ]
        )
    DBSession.commit()
    print(
        "SQLAlchemy ORM bulk_save_objects(): Total time for " + str(n) +
        " records " + str(time.time() - t0) + " secs")


def test_sqlalchemy_core(n=100000):
    init_sqlalchemy()
    t0 = time.time()
    engine.execute(
        Customer.__table__.insert(),
        [{"name": 'NAME ' + str(i)} for i in xrange(n)]
    )
    print(
        "SQLAlchemy Core: Total time for " + str(n) +
        " records " + str(time.time() - t0) + " secs")


def init_sqlite3(dbname):
    conn = sqlite3.connect(dbname)
    c = conn.cursor()
    c.execute("DROP TABLE IF EXISTS customer")
    c.execute(
        "CREATE TABLE customer (id INTEGER NOT NULL, "
        "name VARCHAR(255), PRIMARY KEY(id))")
    conn.commit()
    return conn


def test_sqlite3(n=100000, dbname='sqlite3.db'):
    conn = init_sqlite3(dbname)
    c = conn.cursor()
    t0 = time.time()
    for i in xrange(n):
        row = ('NAME ' + str(i),)
        c.execute("INSERT INTO customer (name) VALUES (?)", row)
    conn.commit()
    print(
        "sqlite3: Total time for " + str(n) +
        " records " + str(time.time() - t0) + " sec")

if __name__ == '__main__':
    test_sqlalchemy_orm(100000)
    test_sqlalchemy_orm_pk_given(100000)
    test_sqlalchemy_orm_bulk_insert(100000)
    test_sqlalchemy_core(100000)
    test_sqlite3(100000)

1
ขอบคุณ. เป็นประโยชน์และทั่วถึงจริงๆ
Steve B.

ฉันเห็นอีกตัวอย่างหนึ่งที่ใช้ bindparams ไวยากรณ์ดูรวบรัดดีไหม?
Jay

35

เท่าที่ฉันทราบไม่มีวิธีใดที่จะทำให้ ORM ออกเม็ดมีดจำนวนมากได้ ฉันเชื่อว่าเหตุผลพื้นฐานคือ SQLAlchemy จำเป็นต้องติดตามข้อมูลประจำตัวของแต่ละออบเจ็กต์ (เช่นคีย์หลักใหม่) และส่วนแทรกจำนวนมากเข้าไปยุ่งเกี่ยวกับสิ่งนั้น ตัวอย่างเช่นสมมติว่าfooตารางของคุณมีidคอลัมน์และแมปกับFooคลาส:

x = Foo(bar=1)
print x.id
# None
session.add(x)
session.flush()
# BEGIN
# INSERT INTO foo (bar) VALUES(1)
# COMMIT
print x.id
# 1

เนื่องจาก SQLAlchemy รับค่าx.idโดยไม่ต้องออกแบบสอบถามอื่นเราจึงสามารถสรุปได้ว่าได้รับค่าโดยตรงจากINSERTคำสั่ง หากคุณไม่ต้องการการเข้าถึงวัตถุที่สร้างขึ้นในภายหลังผ่านอินสแตนซ์เดียวกันคุณสามารถข้ามเลเยอร์ ORM สำหรับส่วนแทรกของคุณได้:

Foo.__table__.insert().execute([{'bar': 1}, {'bar': 2}, {'bar': 3}])
# INSERT INTO foo (bar) VALUES ((1,), (2,), (3,))

SQLAlchemy ไม่สามารถจับคู่แถวใหม่เหล่านี้กับออบเจ็กต์ใด ๆ ที่มีอยู่ได้ดังนั้นคุณจะต้องสอบถามใหม่สำหรับการดำเนินการในภายหลัง

เท่าที่เกี่ยวข้องกับข้อมูลเก่าคุณควรจำไว้ว่าเซสชันไม่มีวิธีในตัวที่จะทราบได้ว่าเมื่อใดที่ฐานข้อมูลมีการเปลี่ยนแปลงนอกเซสชัน เพื่อที่จะปรับเปลี่ยนการเข้าถึงข้อมูลจากภายนอกผ่านทางอินสแตนซ์ที่มีอยู่กรณีจะต้องมีการทำเครื่องหมายว่าหมดอายุ นี้เกิดขึ้นโดยเริ่มต้นในsession.commit()แต่สามารถทำได้ด้วยตนเองโดยการเรียกหรือsession.expire_all() session.expire(instance)ตัวอย่าง (ละเว้น SQL):

x = Foo(bar=1)
session.add(x)
session.commit()
print x.bar
# 1
foo.update().execute(bar=42)
print x.bar
# 1
session.expire(x)
print x.bar
# 42

session.commit()หมดอายุxดังนั้นคำสั่งการพิมพ์ครั้งแรกจะเปิดธุรกรรมใหม่โดยปริยายและxแอตทริบิวต์ของการสืบค้นใหม่ หากคุณแสดงความคิดเห็นในใบแจ้งยอดการพิมพ์ครั้งแรกคุณจะสังเกตเห็นว่าคำสั่งที่สองรับค่าที่ถูกต้องแล้วเนื่องจากแบบสอบถามใหม่จะไม่ถูกปล่อยออกมาจนกว่าจะมีการอัปเดต

สิ่งนี้สมเหตุสมผลจากมุมมองของการแยกธุรกรรม - คุณควรเลือกเฉพาะการแก้ไขภายนอกระหว่างธุรกรรมเท่านั้น session.expire_all()ถ้านี่เป็นสาเหตุที่ทำให้คุณเดือดร้อนผมขอแนะนำให้ชัดเจนอีกครั้งหรือคิดโปรแกรมประยุกต์ของคุณขอบเขตการทำธุรกรรมแทนทันทีถึงการ


ขอบคุณสำหรับการตอบกลับฉันจะไปให้ WRT ปัญหาที่กำลังจะหมดอายุสิ่งที่ฉันเห็นไม่เหมือนกันเลย ฉันใช้เซสชันที่กำหนดขอบเขตในเทอร์โบเกียร์ การดำเนินการ getSession (). query (Foo) .filter .... all () ส่งคืนสิ่งที่แตกต่างกันขึ้นอยู่กับการร้องขอและยังไม่ส่งคืนระเบียนที่อัปเดตที่อยู่ในฐานข้อมูลจนกว่าฉันจะเริ่มต้นใหม่ ฉันแก้ไขปัญหานี้ด้วยการทำ autocommit = True และเพิ่มบางสิ่งที่. remove () d เซสชันหลังจากที่คำขอเสร็จสมบูรณ์ (ฉันรวบรวมคุณตั้งใจที่จะทำเช่นนั้น)
Nick Holden

ฉันเดาว่ามันส่งคืนสิ่งที่แตกต่างกันขึ้นอยู่กับคำขอเนื่องจากมีเซสชันที่กำหนดขอบเขตต่อเธรดในพูลและเซสชันอยู่ในสถานะที่ต่างกัน? ดูเหมือนจะแปลกเล็กน้อยที่ sa จะไม่ได้รับข้อมูลใหม่หลังจากมีการร้องขอใหม่ ฉันคิดว่าฉันเข้าใจผิดว่า autocommit = False กำลังทำอะไรอยู่
Nick Holden

ด้วยautocommit=Falseฉันเชื่อว่าคุณควรโทรsession.commit()ตามคำขอที่เสร็จสมบูรณ์ (ฉันไม่คุ้นเคยกับ TurboGears ดังนั้นอย่าสนใจสิ่งนี้หากมีการจัดการสำหรับคุณในระดับเฟรมเวิร์ก) นอกจากตรวจสอบให้แน่ใจว่าการเปลี่ยนแปลงของคุณได้ทำกับฐานข้อมูลแล้วการเปลี่ยนแปลงนี้จะทำให้ทุกอย่างในเซสชันหมดอายุ ธุรกรรมถัดไปจะไม่เริ่มต้นจนกว่าจะมีการใช้เซสชันนั้นครั้งถัดไปดังนั้นคำขอในอนาคตในเธรดเดียวกันจะไม่เห็นข้อมูลเก่า
dhaffey

10
รูปแบบทางเลือก:session.execute(Foo.__table__.insert(), values)
Joril

6
โปรดทราบว่า sqlalchemy รุ่นใหม่กว่ามีความสามารถในการแทรกจำนวนมาก: docs.sqlalchemy.org/en/latest/orm/…
Wayne Werner

18

ฉันมักจะทำโดยใช้add_all.

from app import session
from models import User

objects = [User(name="u1"), User(name="u2"), User(name="u3")]
session.add_all(objects)
session.commit()

2
แน่ใจหรือว่าใช้งานได้ มันไม่เพียงแค่ทำสิ่งที่เทียบเท่า.addกับเซสชันทีละครั้งเท่านั้น?
Alec

นั่นจะเป็นการตอบโต้ที่ใช้งานง่ายเมื่อใช้ชื่อวิธีการเอกสารไม่ได้ลงรายละเอียด: Add the given collection of instances to this Session.คุณมีเหตุผลใดที่เชื่อว่ามันไม่ได้ทำการแทรกจำนวนมากหรือไม่?
reubano

3
ฉันไม่คิดว่ามันจะย้อนแย้งเกินไป - อันที่จริงแล้วมันเพิ่ม ทุกสิ่งที่คุณขอให้ ไม่มีอะไรเกี่ยวกับการเพิ่มทุกสิ่งในเซสชันดูเหมือนว่ามันจะบ่งบอกถึงสิ่งที่คำสั่ง SQL ที่เป็นพื้นฐานได้รับ ดูแหล่งที่มา: github.com/zzzeek/sqlalchemy/blob/…ในความเป็นจริงดูเหมือนจะเป็นเพียง.addแต่ละรายการ
Alec

มันทำงานได้ดีเมื่อเทียบbulk_save_objects()กับ a flush()เราสามารถรับ ID ของออบเจ็กต์ได้ แต่bulk_save_objects()ทำไม่ได้ (เหตุการณ์ที่flush()เรียกว่า)
coanor

14

เพิ่มการสนับสนุนโดยตรงใน SQLAlchemy ในเวอร์ชัน 0.8

ตามเอกสาร , connection.execute(table.insert().values(data))ควรทำเคล็ดลับ (โปรดทราบว่าสิ่งนี้ไม่เหมือนกับconnection.execute(table.insert(), data)ที่ส่งผลให้มีการแทรกแถวแต่ละแถวผ่านการเรียกไปยังexecutemany) ในทุกอย่างยกเว้นการเชื่อมต่อในพื้นที่ความแตกต่างของประสิทธิภาพอาจเป็นเรื่องใหญ่


คุณช่วยชี้แจงได้ไหมว่าอันไหนมีประสิทธิภาพมากกว่ากัน?
Jacob Lee

10

SQLAlchemy เปิดตัวในเวอร์ชัน1.0.0:

การดำเนินการจำนวนมาก - เอกสาร SQLAlchemy

ด้วยการดำเนินการเหล่านี้คุณสามารถทำการแทรกหรืออัปเดตจำนวนมากได้แล้ว!

ตัวอย่างเช่น (หากคุณต้องการค่าโสหุ้ยต่ำสุดสำหรับการแทรกตารางธรรมดา) คุณสามารถใช้Session.bulk_insert_mappings():

loadme = [(1, 'a'),
          (2, 'b'),
          (3, 'c')]
dicts = [dict(bar=t[0], fly=t[1]) for t in loadme]

s = Session()
s.bulk_insert_mappings(Foo, dicts)
s.commit()

หรือถ้าคุณต้องการให้ข้ามloadmetuples และเขียนพจนานุกรมลงในโดยตรงdicts(แต่ฉันคิดว่ามันง่ายกว่าที่จะทิ้งความเป็นระเบียบทั้งหมดออกจากข้อมูลและโหลดรายการพจนานุกรมแบบวนซ้ำ)


7

คำตอบของ Piere นั้นถูกต้อง แต่ปัญหาหนึ่งคือbulk_save_objectsโดยค่าเริ่มต้นจะไม่ส่งคืนคีย์หลักของวัตถุหากเป็นเรื่องที่คุณกังวล ตั้งค่าreturn_defaultsเพื่อTrueรับพฤติกรรมนี้

เอกสารที่ได้คือที่นี่

foos = [Foo(bar='a',), Foo(bar='b'), Foo(bar='c')]
session.bulk_save_objects(foos, return_defaults=True)
for foo in foos:
    assert foo.id is not None
session.commit()

2
ต้องใช้ความระมัดระวังกับธง มันจะแทรกวัตถุทีละชิ้นตามลำดับและประสิทธิภาพที่เพิ่มขึ้นอย่างมีนัยสำคัญอาจไม่อยู่ที่นั่น [1] ในกรณีของฉันประสิทธิภาพลดลงซึ่งฉันสงสัยเนื่องจากค่าใช้จ่าย [1]: docs.sqlalchemy.org/en/13/orm/…
dhfromkorea

6

ถนนทุกสายมุ่งสู่กรุงโรมแต่ถนนบางสายข้ามภูเขาต้องใช้เรือข้ามฟาก แต่ถ้าคุณต้องการไปที่นั่นอย่างรวดเร็วให้ใช้มอเตอร์เวย์


ในกรณีนี้มอเตอร์เวย์คือการใช้execute_batch ()คุณสมบัติของpsycopg2 เอกสารระบุว่าดีที่สุด:

การใช้งานปัจจุบันของ executemany()คือ (โดยใช้คำพูดที่เป็นกุศลอย่างยิ่ง) ไม่ได้ดำเนินการโดยเฉพาะ ฟังก์ชันเหล่านี้สามารถใช้เพื่อเร่งความเร็วในการดำเนินการคำสั่งซ้ำ ๆ กับชุดพารามิเตอร์ executemany()โดยการลดจำนวนถกเซิร์ฟเวอร์ประสิทธิภาพการทำงานที่สามารถเป็นคำสั่งของขนาดดีกว่าการใช้

ในการทดสอบของฉันเองexecute_batch()นั้นเร็วกว่าประมาณสองเท่าexecutemany()และให้ตัวเลือกในการกำหนดค่า page_size สำหรับการปรับเปลี่ยนเพิ่มเติม (ถ้าคุณต้องการที่จะบีบช่วง 2-3% ของประสิทธิภาพการทำงานที่ออกมาจากคนขับรถ)

คุณสมบัติเดียวกันนี้สามารถเปิดใช้งานได้อย่างง่ายดายหากคุณใช้ SQLAlchemy โดยการตั้งค่าuse_batch_mode=Trueเป็นพารามิเตอร์เมื่อคุณสร้างอินสแตนซ์เครื่องยนต์ด้วยcreate_engine()


หมายเหตุ: psycopg2 ของexecute_valuesเป็นเร็วขึ้นกว่า psycopg2 ของexecute_batchเมื่อทำใส่กลุ่ม!
Fierr

5

นี่คือวิธี:

values = [1, 2, 3]
Foo.__table__.insert().execute([{'bar': x} for x in values])

สิ่งนี้จะแทรกดังนี้:

INSERT INTO `foo` (`bar`) VALUES (1), (2), (3)

การอ้างอิง: คำถามที่พบบ่อยของ SQLAlchemy มีการวัดประสิทธิภาพสำหรับวิธีการคอมมิตต่างๆ


3

คำตอบที่ดีที่สุดที่ฉันพบคือในเอกสาร sqlalchemy:

http://docs.sqlalchemy.org/en/latest/faq/performance.html#im-inserting-400-000-rows-with-the-orm-and-it-s-really-slow

มีตัวอย่างที่สมบูรณ์ของเกณฑ์มาตรฐานของโซลูชันที่เป็นไปได้

ตามที่แสดงในเอกสาร:

Bulk_save_objects ไม่ใช่วิธีแก้ปัญหาที่ดีที่สุด แต่ประสิทธิภาพถูกต้อง

การใช้งานที่ดีที่สุดอันดับสองในแง่ของความสามารถในการอ่านฉันคิดว่ามาพร้อมกับ SQLAlchemy Core:

def test_sqlalchemy_core(n=100000):
    init_sqlalchemy()
    t0 = time.time()
    engine.execute(
        Customer.__table__.insert(),
            [{"name": 'NAME ' + str(i)} for i in xrange(n)]
    )

บริบทของฟังก์ชันนี้มีให้ในบทความเอกสารประกอบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.