2012-10-29 42 views

Trả lời

6

It doesn't look like it.

Bạn có thể phải sử dụng psycopg2 để hiển thị chức năng này và bỏ qua các khả năng ORM. Tôi đoán tôi không thực sự thấy lợi ích của ORM trong một hoạt động như vậy anyway vì nó là một chèn số lượng lớn thẳng và đối phó với các đối tượng cá nhân một la một ORM sẽ không thực sự làm cho một toàn bộ rất nhiều ý nghĩa.

+2

siêu - có thể truy cập psycopg qua engine.raw_connection() – EoghanM

20

câu trả lời được chấp nhận là đúng nhưng nếu bạn muốn nhiều hơn chỉ là nhận xét của EoghanM đi trên sau đây làm việc cho tôi trong việc sao chép một bảng ra CSV ...

from sqlalchemy import sessionmaker, create_engine 

eng = create_engine("postgresql://user:[email protected]:5432/db") 
ses = sessionmaker(bind=engine) 

dbcopy_f = open('/tmp/some_table_copy.csv','wb') 

copy_sql = 'COPY some_table TO STDOUT WITH CSV HEADER' 

fake_conn = eng.raw_connection() 
fake_cur = fake_conn.cursor() 
fake_cur.copy_expert(copy_sql, dbcopy_f) 

Các sessionmaker là không cần thiết nhưng nếu bạn đang có thói quen tạo động cơ và phiên làm việc cùng lúc để sử dụng raw_connection, bạn sẽ cần tách riêng chúng (trừ khi có cách nào đó để truy cập công cụ thông qua đối tượng phiên mà tôi không biết). Chuỗi sql được cung cấp cho copy_expert cũng không phải là cách duy nhất cho nó, có chức năng cơ bản copy_to mà bạn có thể sử dụng với tập hợp con các tham số mà bạn có thể truy cập vào truy vấn thông thường COPY ĐỂ truy vấn. Hiệu suất tổng thể của lệnh có vẻ nhanh đối với tôi, sao chép ra một bảng ~ 20.000 hàng.

http://initd.org/psycopg/docs/cursor.html#cursor.copy_to http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.raw_connection

+0

Đây là một tìm kiếm tuyệt vời. Điều này làm giảm thời gian của tôi tiết kiệm dữ liệu từ 8 giờ + qua đêm đến chỉ 4 phút hoặc lâu hơn. Ôi trơi! – trench

+0

Làm việc cho tôi, nhưng tôi phải làm 'fake_conn.commit()' ở cuối – Michael

11

Nếu động cơ của bạn được cấu hình với một chuỗi kết nối psycopg2 (đó là mặc định, do đó, hoặc "postgresql://..." hoặc "postgresql+psycopg2://..."), bạn có thể tạo ra một con trỏ psycopg2 từ một phiên SQL Alchemy sử dụng

cursor = session.connection().connection.cursor() 

mà bạn có thể sử dụng để thực thi

cursor.copy_from(...) 

Con trỏ sẽ hoạt động trong cùng một giao dịch như phiên của bạn hiện tại. Nếu xảy ra commit hoặc rollback, việc sử dụng con trỏ thêm một lần nữa là ném psycopg2.InterfaceError, bạn sẽ phải tạo một hình mới.

3

Bạn không cần phải thả xuống psycopg2, sử dụng raw_connection cũng như một con trỏ.

Chỉ cần thực hiện sql như bình thường, thậm chí bạn có thể sử dụng các tham số ràng buộc với text():

engine.execute(text('''copy some_table from :csv 
         delimiter ',' csv''' 
        ).execution_options(autocommit=True), 
       csv='/tmp/a.csv') 

Bạn có thể thả execution_options(autocommit=True) nếu this PR sẽ được chấp nhận

+0

Chỉ tiết lộ rằng đó là kho lưu trữ mã của bạn, có vẻ như là – Drew

+0

Không, cái được liên kết là "PR này" không phải của tôi kho lưu trữ, đó là kho lưu trữ thông thường/chính thức cho sqlalchemy. OTOH PR rõ ràng là của tôi, đó không phải là một bí mật: Tôi sử dụng cùng một tên người dùng trên cả stackoverflow và bitbucket. Nhưng dù sao, tôi đã vấp phải câu hỏi này trong khi nghiên cứu các ví dụ cho sự thay đổi đó, và mọi thứ tôi đã viết đều đúng. Tôi có thể tránh liên kết PR, nhưng (trong trường hợp nó sẽ được chấp nhận) thì câu trả lời này sẽ gợi ý một đoạn trích lỗi thời, trừ khi tôi hoặc ai đó sẽ nhớ cập nhật nó sau khi thực tế – berdario

2

Bạn có thể sử dụng:

def to_sql(engine, df, table, if_exists='fail', sep='\t', encoding='utf8'): 
    # Create Table 
    df[:0].to_sql(table, engine, if_exists=if_exists) 

    # Prepare data 
    output = cStringIO.StringIO() 
    df.to_csv(output, sep=sep, header=False, encoding=encoding) 
    output.seek(0) 

    # Insert data 
    connection = engine.raw_connection() 
    cursor = connection.cursor() 
    cursor.copy_from(output, table, sep=sep, null='') 
    connection.commit() 
    cursor.close() 

Tôi chèn 200000 dòng trong 5 giây thay vì 4 phút

.210
+0

Bạn có thể cung cấp một số chi tiết về những gì ' đối tượng df' là gì? – EoghanM

+0

df là một khung dữ liệu gấu trúc –

0

Nếu bạn có thể tới các cơ bạn có tất cả các bạn cần phải làm điều này:

engine = create_engine('postgresql+psycopg2://myuser:[email protected]/mydb') 
# or 
engine = session.engine 
# or any other way you know to get to the engine 

Bây giờ bạn có thể làm việc.

# isolate a connection 
connection = engine.connect().connection 

# get the cursor 
cursor = connection.cursor() 

Dưới đây là một số mẫu cho các tuyên bố COPY để sử dụng với cursor.copy_expert(), một lựa chọn hoàn chỉnh hơn và linh hoạt hơn copy_from() hoặc copy_to() vì nó được chỉ định ở đây: http://initd.org/psycopg/docs/cursor.html#cursor.copy_expert.

# to dump to a file 
dump_to = """ 
COPY mytable 
TO STDOUT 
WITH (
    FORMAT CSV, 
    DELIMITER ',', 
    HEADER 
); 
""" 

# to copy from a file: 
copy_from = """ 
COPY mytable 
FROM STDIN 
WITH (
    FORMAT CSV, 
    DELIMITER ',', 
    HEADER 
); 
""" 

Kiểm tra các tùy chọn trên có nghĩa là gì và những người khác có thể quan tâm đến tình huống cụ thể của bạn https://www.postgresql.org/docs/current/static/sql-copy.html.

LƯU Ý QUAN TRỌNG: Liên kết đến tài liệu của cursor.copy_expert() cho biết sử dụng STDOUT để ghi ra tệp và STDIN để sao chép từ tệp. Nhưng nếu bạn nhìn vào cú pháp trên hướng dẫn sử dụng PostgreSQL, bạn sẽ thấy rằng bạn cũng có thể chỉ định tệp cần ghi vào hoặc trực tiếp trong câu lệnh COPY. Đừng làm điều đó, bạn có thể lãng phí thời gian của bạn nếu bạn không chạy root (người chạy Python như root trong quá trình phát triển?) Chỉ cần làm những gì được chỉ ra trong tài liệu của psycopg2 và chỉ định STDIN hoặc STDOUT trong câu lệnh của bạn với cursor.copy_expert() , nó sẽ ổn thôi.

# running the copy statement 
with open('/path/to/your/data/file.csv') as f: 
    cursor.copy_expert(copy_from, file=f) 

# don't forget to commit the changes. 
connection.commit() 
Các vấn đề liên quan