python-oracledb

repository·main·Indexed 19 days ago

https://github.com/oracle/python-oracledb

A high-performance, lightweight Python extension module and successor to cx_Oracle that allows Python programs to connect directly to Oracle Database. It supports two modes: Thin mode (connecting directly to Oracle Database 12.1 or later) and Thick mode (requiring Oracle Client libraries for advanced functionality and support for Oracle Database 11.2 or later). Compatible with Python 3.10 through 3.15.

Tokens
172.1K
Snippets
474
Records
667
Agent score
63%

What's inside python-oracledb

  1. Feature highlights of python-oracledb

    main

    python-oracledb provides a high-performance interface for Oracle Database with the following key capabilities:

    • SQL/PL/SQL Execution: Optimized with compressed fetch, pre-fetching, client/server result set caching, and auto-tuning statement caching.
    • Data Type Support: Extensive support including JSON, VECTOR, LOBs (CLOB/BLOB), and SQL object binding.
    • DataFrame Integration: Efficient fetching and inserting for libraries like Pandas, Polars, NumPy, PyArrow, PyTorch, and Apache Parquet.
    • Advanced Database Features: Support for Oracle Database Direct Path Loads, connection pooling, and Deep Data Security.
    • Network Features: Full use of Oracle Network Service infrastructure, including encrypted traffic.
    • API Compliance: Conforms to the Python Database API v2.0 Specification (PEP 249).
  2. License agreement for python-oracledb

    main

    python-oracledb is dual-licensed. You may choose to use the software under either the Universal Permissive License (UPL) 1.0 or the Apache License 2.0.

    If you choose the Apache License 2.0, the standard terms and conditions of that license apply.

  3. Batch Statement and Bulk Copy Operations Overview

    main

    Python-oracledb provides optimized mechanisms for large-scale ETL (Extract, Transform, Load) operations and efficient data ingestion. You can optimize batch insertions, handle 'noisy' data (values in unsuitable formats) by filtering them for review while continuing to insert valid values, and utilize several high-performance loading strategies:

    • Array DML: Standard batch loading for Oracle Database.
    • Direct Path Loads: Used for very fast loading of large datasets when specific schema criteria are met.
    • Memoptimized Loads: Recommended for frequent, small inserts.

    For further optimization, refer to tuning and dataframe format documentation.

  4. Use containerized examples and notebooks

    main

    The repository provides alternative ways to explore python-oracledb:

    • Containers: The containers/ directory contains Dockerfiles for building a development environment that includes both the samples and a running Oracle Database.
    • Notebooks: The notebooks/ directory contains Jupyter notebooks with runnable examples for interactive exploration.
  5. What is Pipelining and when to use it

    main

    Pipelining allows an application to send multiple, independent statements to Oracle Database in a single call. This reduces network round-trips, which is most beneficial when performing many small operations in rapid succession or when the network to the database is slow.

    Key Characteristics:

    • Sequential Execution: Operations are executed sequentially by the database, not concurrently. Pipelining improves application responsiveness by allowing the application to perform non-database work while the database processes the pipeline.
    • Thin Mode & asyncio: Pipelining is only supported in python-oracledb Thin mode with asyncio.
    • Database Requirement: True pipelining (with round-trip reduction) requires Oracle AI Database 26ai or later. On older databases, operations are executed sequentially by the driver, providing no performance benefit but allowing for code portability.
    • Limitations: Query results or OUT binds from one operation cannot be passed to subsequent operations within the same pipeline.
  6. What is Implicit Connection Pooling and when to use it

    main

    Implicit connection pooling is an option for applications that cause excessive database server load due to many standalone connections but cannot be easily rewritten to use python-oracledb connection pooling.

    It allows application connections to share pooled servers in DRCP (Database Resident Connection Pooling) or Oracle Connection Manager in Traffic Director Mode's (CMAN-TDM) Proxy Resident Connection Pooling (PRCP).

    Key Characteristics:

    • No code changes required: Applications do not need to be modified to acquire or release connections explicitly.
    • Automatic lifecycle: Connections are internally acquired from the pool when used and released back to the pool when not in use (potentially between oracledb.connect() and Connection.close()).
    • Availability: Works in both Thin and Thick modes.
    • Requirements: Requires Oracle Database 26ai. Thick mode also requires Oracle Client version 23 libraries.

    Warning: It is recommended to use python-oracledb's local connection pooling instead of implicit connection pooling whenever possible, as local pooling provides better control over server reuse.

  7. What is Oracle Deep Data Security and how to use it

    main

    Oracle Deep Data Security is a database-enforced authorization framework for Oracle Database 26ai that provides fine-grained access control at the row, column, and cell levels.

    To use it, an application must send an end-user security context payload to the database. This payload contains identity and authorization details such as an end-user identity, a database-access token, data roles, and context attributes.

    Key Requirements:

    • Requires Oracle Database 26ai.
    • Supported only in python-oracledb Thin mode.

    You can manage this context in two ways:

    1. Manually: Using oracledb.create_end_user_security_context() and setting it on a connection.
    2. Automatically: Using the end_user_sec_provider plugin to handle token acquisition and context setting.
  8. What is Database Resident Connection Pooling (DRCP)?

    main

    Database Resident Connection Pooling (DRCP) enables database resource sharing for applications using a large number of connections across multiple client processes or application servers. Instead of each Python connection using a dedicated database server process, DRCP allows pooling of these processes, reducing memory requirements on the database host.

    When to use DRCP:

    • Applications sharing the same database credentials and similar session settings (e.g., date formats).
    • Applications that acquire a connection, perform short-duration work, and release it quickly.
    • Applications that cannot use a local driver connection pool but still need performance benefits from process reuse.

    Best Practices:

    • Use DRCP in conjunction with python-oracledb's local connection pool (oracledb.create_pool() or oracledb.create_pool_async()) for maximum efficiency.
    • Avoid using DRCP for long-running operations.
    • Always specify a connection class (cclass) to allow optimal session reuse.
  9. Understand Connection Pooling options

    main

    Connection pooling improves performance by reusing existing database connections instead of the expensive process of creating new ones. python-oracledb provides several pooling solutions:

    • Driver Connection Pools: Managed by the driver layer. Best for applications with many users performing short-duration database work. Created via oracledb.create_pool() or oracledb.create_pool_async(). Recommended for most performance and scalability needs.
    • DRCP (Database Resident Connection Pooling): Pools server processes on the database host. Useful for a large number of application connections (e.g., multiple application processes). It is recommended to use DRCP in conjunction with a driver connection pool.
    • PRCP (Proxy Resident Connection Pooling): Handled by Oracle's mid-tier connection proxy (CMAN-TDM).
    • Implicit Connection Pooling: Automatically detects when applications are not performing database work and allows the server process to be used by others. Ideal for legacy applications that cannot be updated to use explicit driver pools.
  10. Connect to Oracle Globally Distributed Database (Sharding)

    main

    Oracle Globally Distributed Database (formerly Oracle Sharding) allows data to be distributed across a pool of databases.

    Note: This feature is only supported in python-oracledb Thick mode.

    To route a connection directly to a specific shard, use the shardingkey and (if using composite sharding) supershardingkey parameters in oracledb.connect() or ConnectionPool.acquire().

    Key Details:

    • Sharding Key: A required sequence of values used to route to a shard. Supported types: string (VARCHAR2), number (NUMBER), bytes (RAW), and date (DATE). TIMESTAMP is not supported.
    • Super Sharding Key: Required when using composite sharding (partitioning by a range/list, then by a shard key).
    • Connection Pooling: Use the max_sessions_per_shard attribute in oracledb.create_pool() to balance connections across shards.
    • Coordinator Shard: To access data across multiple shards, connect to the coordinator shard catalog database without providing shard keys.
    # Sharding by VARCHAR2
    connection = oracledb.connect(user="hr", password=userpwd,
                                  dsn="dbhost.example.com/orclpdb",
                                  shardingkey=["SCOTT"])
    
    # Sharding by NUMBER
    connection = oracledb.connect(user="hr", password=userpwd,
                                  dsn="dbhost.example.com/orclpdb",
                                  shardingkey=[110])
    
    # Sharding by DATE
    import datetime
    d = datetime.datetime(2014, 7, 3)
    connection = oracledb.connect(user="hr", password=userpwd,
                                  dsn="dbhost.example.com/orclpdb",
                                  shardingkey=[d])
    
    # Sharding by RAW
    b = b'\x01\x04\x08'
    connection = oracledb.connect(user="hr", password=userpwd,
                                  dsn="dbhost.example.com/orclpdb",
                                  shardingkey=[b])
    
    # Multiple keys (Composite Sharding)
    key_list = [70, "SCOTT", "gold", b'\x00\x01\x02']
    connection = oracledb.connect(user="hr", password=userpwd,
                                  dsn="dbhost.example.com/orclpdb",
                                  shardingkey=key_list)
    
    # Using a Super Sharding Key
    connection = oracledb.connect(user="hr", password=userpwd,
                                  dsn="dbhost.example.com/orclpdb",
                                  supershardingkey=["goldclass"],
                                  shardingkey=["SCOTT"])
  11. Use DataFrame objects for high-performance data fetching

    main

    Python-oracledb can fetch query results directly into DataFrame objects. These objects expose an Apache Arrow PyCapsule interface, allowing them to be used efficiently with numerical and data analysis libraries (like pandas or polars) without manual conversion overhead.

    DataFrame objects are returned by the following connection methods:

    • Connection.fetch_df_all()
    • Connection.fetch_df_batches()
    • AsyncConnection.fetch_df_all()
    • AsyncConnection.fetch_df_batches()
    # Example pattern for fetching a DataFrame
    # (Requires a connection object 'conn')
    df = conn.fetch_df_all("SELECT * FROM my_table")
  12. Manage transactions with commit and rollback

    main

    By default, changes are not committed to the database. You must explicitly call Connection.commit() to make changes visible to other users. If your application finishes without an explicit commit, an implicit rollback occurs.

    • Commit changes: Call connection.commit() (note: commit is performed on the Connection object, not the Cursor).
    • Rollback changes: Call connection.rollback() to undo pending changes.
    • Autocommit: Setting Connection.autocommit = True automatically commits every statement. Use this cautiously as it can increase database load and impact transactional consistency.
    connection.commit()