データベースを利用するアプリケーション開発において、SQLクエリの管理と実行は重要な課題です。
特に、AWS Lambdaのようなサーバーレス環境で開発を行う場合、効率的な開発と検証プロセスが求められます。
本記事では、PythonとTiDB Serverlessを使ってSQLクエリを管理し、
ローカル環境での検証とAWS Lambda上での実行を効率化する方法を紹介します。
TiDB Serverlessは、MySQLと互換性のあるサーバーレスのデータベースです。
DBサーバーを自分で構築する手間が省けるので、検証には最適と言えます。
検証であれば、無料で使える枠が用意されています。
ローカル環境での開発とSQL検証の重要性
AWS Lambda上で直接開発を行うことは、以下のような理由から非効率的です。
- Lambda関数の実行にはコストがかかる
- Lambda上での開発ツールは、ローカル環境ほど充実していない
- Lambda上でのデバッグとテストは時間がかかる
そのため、SQLクエリの検証はローカル環境で行うことをお勧めします。
ローカル環境では、充実した開発ツールを使ってクエリの動作を確認し、必要な修正を加えることができます。
Lambda関数にも無料枠はあります。
しかし、工夫をしなければLambda関数上での開発は非効率です。
コードとSQLの分離によるメリット
本事例では、SQLクエリをPythonコードから分離し、combined_queries.sqlというファイルで管理しています。
このファイルを用いた開発方法は、次の記事をご覧ください。
この方法には、以下のようなメリットがあります。
- SQLクエリの再利用性が向上する
- コードの可読性とメンテナンス性が向上する
- ローカル環境とLambda関数間でのクエリの共有が容易になる
ローカル環境で検証したSQLクエリを、Lambda関数にデプロイする際は、combined_queries.sqlファイルを更新するだけで済みます。
これにより、開発と検証のプロセスが大幅に効率化されます。
ローカル環境でのSQL検証
ローカル環境でSQLクエリを検証するには、以下のPythonコードを使用します。
import pymysql
import time
from config import Config
config = Config()
db_config = {
'host': config.tidb_host,
'port': 4000,
'user': config.tidb_user,
'password': config.tidb_password,
'database': config.tidb_db_name,
'ssl_verify_cert': True,
'ssl_verify_identity': True,
'ssl_ca': config.ca_path
}
def get_query(query_name):
with open('combined_queries.sql', 'r', encoding='utf-8') as file:
content = file.read()
query_start = content.find(f'-- [{query_name}]\n')
if query_start == -1:
raise ValueError(f"Query '{query_name}' not found.")
query_end = content.find('-- [', query_start + 1)
if query_end == -1:
query_end = len(content)
query_text = content[query_start:query_end].strip()
query_lines = query_text.split('\n')
query = query_lines[-1].strip()
return query
def execute_query(query_name, params):
query = get_query(query_name)
query = query.replace('?', '%s') # プレースホルダーを%sに変換
connection = pymysql.connect(**db_config)
cursor = connection.cursor()
start_time = time.perf_counter()
cursor.execute(query, params)
data = cursor.fetchall()
end_time = time.perf_counter()
cursor.close()
connection.close()
return data, end_time - start_time
def main():
city_id = 300
data, execution_time = execute_query('get_city_data_by_id', (city_id,))
print(f"Result of get_city_data_by_id (city_id {city_id}): {data}")
print(f"Execution time: {execution_time:.5f} seconds")
print()
if __name__ == '__main__':
main()
get_query関数でcombined_queries.sqlからクエリを取得し、execute_query関数でTiDBに接続してクエリを実行しています。
ローカル環境では、TiDBの接続情報をdb_config変数で管理する形となります。
具体的には、.envファイルに設定情報を登録しています。
その.envをpython-dotenvで読み込んでいるということです。
このコードを使って、ローカル環境でSQLクエリの動作を確認し、必要な修正を加えます。
なお、データにはMySQLのサンプルデータベースである「world database」を利用しています。
TiDB Serverlessの管理画面で次のように確認できます。

Lambda関数へのデプロイ
ローカル環境で検証したSQLクエリをLambda関数で使用するには、以下の手順を実行します。
- combined_queries.sqlファイルをLambda関数のデプロイパッケージに含める
- Lambda関数のコードを更新する
Lambda関数のコードは、以下のようになります。
import pymysql
import time
import os
def get_query(query_name):
with open('combined_queries.sql', 'r', encoding='utf-8') as file:
content = file.read()
query_start = content.find(f'-- [{query_name}]\n')
if query_start == -1:
raise ValueError(f"Query '{query_name}' not found.")
query_end = content.find('-- [', query_start + 1)
if query_end == -1:
query_end = len(content)
query_text = content[query_start:query_end].strip()
query_lines = query_text.split('\n')
query = query_lines[-1].strip()
return query
def execute_query(query_name, params):
query = get_query(query_name)
query = query.replace('?', '%s') # プレースホルダーを%sに変換
db_config = {
'host': os.environ['TIDB_HOST'],
'port': int(os.environ['TIDB_PORT']),
'user': os.environ['TIDB_USER'],
'password': os.environ['TIDB_PASSWORD'],
'database': os.environ['TIDB_DB_NAME'],
'ssl_verify_cert': True,
'ssl_verify_identity': True,
'ssl_ca': os.environ['CA_PATH']
}
connection = pymysql.connect(**db_config)
cursor = connection.cursor()
start_time = time.perf_counter()
cursor.execute(query, params)
data = cursor.fetchall()
end_time = time.perf_counter()
cursor.close()
connection.close()
return data, end_time - start_time
def lambda_handler(event, context):
city_id = 300
data, execution_time = execute_query('get_city_data_by_id', (city_id,))
print(f"Result of get_city_data_by_id (city_id {city_id}): {data}")
print(f"Execution time: {execution_time:.5f} seconds")
return {
'statusCode': 200,
'body': 'Query executed successfully'
}
Lambda関数では、TiDBの接続情報を環境変数から取得しています。
また、TiDBへの接続にはPyMySQLライブラリを利用しています。
AWS LambdaへのPythonライブラリのインストールは、以下の記事が参考になります。
まとめ
PythonとTiDBを使ってSQLクエリを管理する方法を紹介しました。
SQLクエリをコードから分離することで、再利用性と可読性が向上します。
その結果、ローカル環境とLambda関数間でのクエリの共有が容易になります。
また、ローカル環境でSQLクエリを検証することで、開発と検証のプロセスを大幅に効率化できます。
本事例の方法を採用することで、AWS Lambdaを使ったデータベースアプリケーションの開発と運用の生産性が向上するでしょう。
ちなみに、各環境における検証コードの実行結果は以下となります。
ローカルマシン
Result of get_city_data_by_id (city_id 300): ((300, 'Gravataí', 'BRA', 'Rio Grande do Sul', 223011),) Execution time: 0.01424 seconds
Lambda関数
Result of get_city_data_by_id (city_id 300): ((300, 'Gravataí', 'BRA', 'Rio Grande do Sul', 223011),) Execution time: 0.00859 seconds
Lambda関数は、かなり高速です。
TiDB ServerlessはAWSの東京リージョンで動いていることが判明しています。
そして、Lambda関数も東京リージョンで動かしています。
つまり、TiDB ServerlessとLambda関数はかなり近所である可能性はありますね。






