LoginSignup
1
1

More than 3 years have passed since last update.

[cx_Oracle入門](第13回) コネクションプールを使用した接続(クライアントサイド)

Posted at

連載目次

連載:cx_Oracle入門 目次

検証環境

  • Oracle Cloud利用
  • Oracle Linux 7.7 (VM.Standard2.1)
  • Python 3.6
  • cx_Oracle 8.0
  • Oracle Database 19.5 (ATP, 1OCPU)
  • Oracle Instant Client 18.5

概要

Oracle Databaseの標準の接続方法は、決して早くはありません。むしろ遅いと揶揄されがちです。しかし、コネクションプールの機能を利用することで、他の製品とそん色ない接続性能を出すことが可能です。そして、現在は、サーバーサイド、クライアントサイドの両方でOracle Database自身の機能としてコネクションプールの機能を提供しています。Oracle Databaseでは、Pythonに限らず、どの接続環境であっても、コネクションプールの恩恵を受けることが可能です。
サーバーサイドのコネクションプール機能(DRCP(Database Resident Connection Pool)、データベース常駐接続プーリング)はサーバーサイドの機能故どのような環境でも利用できます。サーバーサイドの設定に興味がある方は以下をご覧ください。とはいえ、DRCPの利用のためには接続時にオプションの指定が必要なので、コーディングが必要な部分は別の回で解説します。今回はクライアントサイドのコネクションプールを対象に解説を行います。

(参考)Oracle Database の DRCP(データベース常駐接続プーリング)の MINSIZE と MAXSIZE を 1 に設定して、複数セッションから接続してみる。

クライアントサイドのコネクションプール

cx_OracleはOracle Clientが持つ、クライアントサイドのコネクションプールの機能を利用するためのAPIを備えています。クライアントサイドのコネクションプールを使用する場合は、まずコネクションプール(セッションプール)を作成します。そしてcx_Oracleオブジェクトのconnect()メソッドではなく、Connectionオブジェクトのacquire()メソッドを使用してプールからセッションを獲得することで、接続が完了します。

sample13a.py
import cx_Oracle
import time

USERID = "admin"
PASSWORD = "FooBar"
DESTINATION = "atp1_low"

# 通常接続の速度計測
t1 = time.time()
connection = cx_Oracle.connect(USERID, PASSWORD, DESTINATION)
t2 = time.time()
connection.close()
print(f"プール未使用時接続時間 : {t2 - t1}秒")

# コネクションプール接続の速度計測
pool = cx_Oracle.SessionPool(USERID, PASSWORD, DESTINATION, min=1, max=2, increment=1)
t1 = time.time()
connection = pool.acquire()
t2 = time.time()
pool.release(connection)
print(f"プール使用時接続時間 : {t2 - t1}秒")

下から6行目でcx_Oracle.SessionPool()をコールしてセッションプール(コネクションプール)を作成しています。最初の3つの引数はConnection.connect()と同様です。4つ目以降の引数は作成するコネクションプールの大きさを指定しています。minは最小の接続数、maxは最大の接続数、incrementはminからmaxまでセッション数を増やす際の増分値です。3個ともサンプル上の値がデフォルト値です。もしアプリケーションがマルチスレッドを使用している場合は、thread引数にTrueを指定してください。
セッション数の増加・減少に伴うパフォーマンスのオーバーヘッドを避けるために、minとmaxの値は同じ値にして、セッション数を固定にすることが推奨されています。指定する数については、アプリケーション稼働状況により調整してください。
確保した接続を終了(解放)する際は、release()メソッドをコールします。引数にacquire()した接続(この例の場合「connection」)を指定してください。

実行結果は大人の事情で掲載できませんが、動かしてみていただければ、圧倒的にコネクションプール使用時の方が高速な接続であることがわかります。ただし、このサンプルではセッションプールの作成時間を接続時間に含めていません。もし含めるとなると、上記例の例の値ならともかく、minの値が大きくなるほど、プール作成に時間を要するので、さすがに通常接続の方が高速になります。
通常接続とコネクションプール利用の使い分けに関しては、バッチ処理のアプリケーションのような、接続回数が1回となるケースが多いアプリケーションでは通常接続を、サーバーレスアプリケーションのような何度もDBに接続することが想定されるようなアプリケーションではコネクションプールを使用するようにするのがよいと考えます。

異種コネクションプールと同種コネクションプール

タイトルの異種(Heterogeneous)と同種(Homogeneous)は、同一コネクションプール内で接続ユーザーをすべて同じにする(同種)か否(異種)かを表します。デフォルトは同種です。今まで説明してきた同種コネクションプールの場合は接続ユーザーは固定となりますが、これから説明する異種コネクションプールの場合はユーザーを混在させることが可能になります。柔軟性に優れる一方、都度認証しないといけないため、接続スピードは同種コネクションプールより低下します。
cx_Oracle.SessionPool()にはhomogeneousというデフォルトTrueの引数が存在します。これをFalseに変更して接続すると、セッション単位に異なるユーザーを指定することが可能になります。ユーザー名とパスワードの指定は、cx_Oracle.SessionPool()ではなく、Connection.acquire()にて行います。

sample13b.py
import cx_Oracle
import time

USERID = "admin"
PASSWORD = "FooBar"
DESTINATION = "atp1_low"

# 同種コネクションプール
pool = cx_Oracle.SessionPool(USERID, PASSWORD, DESTINATION, min=2, max=2)
t1 = time.time()
connection = pool.acquire()
t2 = time.time()
pool.release(connection)
print(f"同種コネクションプール使用時接続時間 : {t2 - t1}秒")

# 異種コネクションプール
pool = cx_Oracle.SessionPool(dsn=DESTINATION, min=2, max=2, homogeneous=False)
t1 = time.time()
connection = pool.acquire(user=USERID, password=PASSWORD)
t2 = time.time()
pool.release(connection)
print(f"異種コネクションプール使用時接続時間 : {t2 - t1}秒")

ユーザー名、パスワード、接続先情報の引数に引数名(それぞれuser, password, dsn)が必須となる点、注意してください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1