Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Tăng tốc to_sql () khi ghi Pandas DataFrame vào cơ sở dữ liệu Oracle bằng SqlAlchemy và cx_Oracle

Pandas + SQLAlchemy theo mặc định lưu tất cả object (chuỗi) cột dưới dạng CLOB trong Oracle DB, giúp chèn cực kỳ chậm.

Dưới đây là một số thử nghiệm:

import pandas as pd
import cx_Oracle
from sqlalchemy import types, create_engine

#######################################################
### DB connection strings config
#######################################################
tns = """
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = my-db-scan)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = my_service_name)
    )
  )
"""

usr = "test"
pwd = "my_oracle_password"

engine = create_engine('oracle+cx_oracle://%s:%[email protected]%s' % (usr, pwd, tns))

# sample DF [shape: `(2000, 11)`]
# i took your 2 rows DF and replicated it: `df = pd.concat([df]* 10**3, ignore_index=True)`
df = pd.read_csv('/path/to/file.csv')

Thông tin DF:

In [61]: df.shape
Out[61]: (2000, 11)

In [62]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2000 entries, 0 to 1999
Data columns (total 11 columns):
id               2000 non-null int64
name             2000 non-null object
premium          2000 non-null float64
created_date     2000 non-null datetime64[ns]
init_p           2000 non-null float64
term_number      2000 non-null int64
uprate           1000 non-null float64
value            2000 non-null int64
score            2000 non-null float64
group            2000 non-null int64
action_reason    2000 non-null object
dtypes: datetime64[ns](1), float64(4), int64(4), object(2)
memory usage: 172.0+ KB

Hãy kiểm tra xem sẽ mất bao lâu để lưu trữ nó vào Oracle DB:

In [57]: df.shape
Out[57]: (2000, 11)

In [58]: %timeit -n 1 -r 1 df.to_sql('test_table', engine, index=False, if_exists='replace')
1 loop, best of 1: 16 s per loop

Trong Oracle DB (chú ý tại CLOB's):

AAA> desc test.test_table
 Name                            Null?    Type
 ------------------------------- -------- ------------------
 ID                                       NUMBER(19)
 NAME                                     CLOB        #  !!!
 PREMIUM                                  FLOAT(126)
 CREATED_DATE                             DATE
 INIT_P                                   FLOAT(126)
 TERM_NUMBER                              NUMBER(19)
 UPRATE                                   FLOAT(126)
 VALUE                                    NUMBER(19)
 SCORE                                    FLOAT(126)
 group                                    NUMBER(19)
 ACTION_REASON                            CLOB        #  !!!

Bây giờ hãy hướng dẫn gấu trúc lưu tất cả object các cột dưới dạng kiểu dữ liệu VARCHAR:

In [59]: dtyp = {c:types.VARCHAR(df[c].str.len().max())
    ...:         for c in df.columns[df.dtypes == 'object'].tolist()}
    ...:

In [60]: %timeit -n 1 -r 1 df.to_sql('test_table', engine, index=False, if_exists='replace', dtype=dtyp)
1 loop, best of 1: 335 ms per loop

Lần này là khoảng. Nhanh hơn 48 lần

Kiểm tra trong Oracle DB:

 AAA> desc test.test_table
 Name                          Null?    Type
 ----------------------------- -------- ---------------------
 ID                                     NUMBER(19)
 NAME                                   VARCHAR2(13 CHAR)        #  !!!
 PREMIUM                                FLOAT(126)
 CREATED_DATE                           DATE
 INIT_P                                 FLOAT(126)
 TERM_NUMBER                            NUMBER(19)
 UPRATE                                 FLOAT(126)
 VALUE                                  NUMBER(19)
 SCORE                                  FLOAT(126)
 group                                  NUMBER(19)
 ACTION_REASON                          VARCHAR2(8 CHAR)        #  !!!

Hãy kiểm tra nó với 200.000 hàng DF:

In [69]: df.shape
Out[69]: (200000, 11)

In [70]: %timeit -n 1 -r 1 df.to_sql('test_table', engine, index=False, if_exists='replace', dtype=dtyp, chunksize=10**4)
1 loop, best of 1: 4.68 s per loop

Mất ~ 5 giây cho 200K hàng DF trong môi trường thử nghiệm của tôi (không phải là nhanh nhất).

Kết luận: sử dụng thủ thuật sau để chỉ định rõ ràng dtype cho tất cả các cột DF của object dtype khi lưu DataFrames vào Oracle DB. Nếu không, nó sẽ được lưu dưới dạng dữ liệu CLOB, loại dữ liệu này cần được xử lý đặc biệt và làm cho nó rất chậm

dtyp = {c:types.VARCHAR(df[c].str.len().max())
        for c in df.columns[df.dtypes == 'object'].tolist()}

df.to_sql(..., dtype=dtyp)


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cài đặt máy khách cơ sở dữ liệu Oracle từng bước

  2. Tại sao CONNECT BY LEVEL trên bảng trả về các hàng thừa?

  3. Cách trả lại Dấu thời gian Unix trong Oracle

  4. NLS_CHARSET_DECL_LEN () Hàm trong Oracle

  5. Lỗi ORA-00932 khi sử dụng lựa chọn với các trường union và CLOB