mssql-pythonのトラブルシューティング

mssql-pythonドライバーを使ってSQL Server、Azure SQL Database、Azure SQL Managed Instance、Microsoft FabricのSQLデータベースに接続する際の一般的な問題を診断し解決しましょう。

インストールの問題

pip install が失敗する、またはソースからビルドされる

症状:

error: Microsoft Visual C++ 14.0 or greater is required
ERROR: Failed building wheel for mssql-python

考えられる原因と解決策:

  • あなたのプラットフォームに合った既製ホイールはありません

    • サポートされているPythonバージョン(3.10以降)とプラットフォームを使っているか確認してください。 互換性マトリックスについては サポートライフサイクル を参照してください。 pip install --upgrade pipでインストールする前にPIPをアップグレードしてください。 リピータブルなチーム環境では、 Repeatable deployments のロックワークフローや Container and local development のコンテナパターンを活用してローカルマシンドリフトを減らしましょう。
  • 仮想環境は未起動

    • まずは仮想環境を起動してください。 システムにPythonをインストールすると、権限エラーや競合が発生することがあります。
    python -m venv .venv
    .venv\Scripts\activate
    pip install mssql-python
    

  • 欠落しているLinuxシステムライブラリ
    • このドライバはLinux上で少数のシステムライブラリを必要とします。 インストールするパッケージについてはプラットフォーム 固有の依存関係 を参照してください。

競合するドライバーのインストール

症状:

同じ環境でmssql-pythonpyodbcをインストールした後にインポートエラーや予期せぬ動作が発生します。

修正:

mssql-python そして pyodbc 共存できる。 競合が見つかった場合は、クリーンな仮想環境を作成しましょう:

python -m venv .venv --clear
.venv\Scripts\activate
pip install mssql-python

接続に関する問題

サーバーに接続できません

症状:

OperationalError: [08001] (0) Client unable to establish connection

考えられる原因と解決策:

  • サーバーにアクセスできません

    • サーバー名とポートが正しいか確認してください。
    • ネットワーク接続を確認してください: ping servernametelnet servername 1433
    • ファイアウォールがポート1433での送信接続を許可していることを確認してください。
  • SQL Serverが動いていません

    • SQL Serverサービスが開始されているか確認してください。
    • 名前付きインスタンスについては、SQL Serverブラウザサービスが稼働しているか確認してください。
  • Azure SQL firewall rules

    • クライアントIPをAzureポータルのAzure SQLファイアウォールルールに追加してください。
    • Azure SQL Managed Instanceの場合は、許可されたネットワークから接続していることを確認してください。
# Test basic connectivity
import socket
try:
    sock = socket.create_connection(("<server>.database.windows.net", 1433), timeout=5)
    print("TCP connection successful")
    sock.close()
except Exception as e:
    print(f"Cannot reach server: {e}")

ログインに失敗しました

症状:

OperationalError: [28000] (18456) Login failed for user 'username'.

考えられる原因と解決策:

  • 認証モードの不一致

    • FabricのAzure SQL Database、Azure SQL Managed Instance、SQLデータベースでは、Authentication=ActiveDirectoryDefaultのようなMicrosoft Entraモードを好む。
    • もし意図的にSQL認証を使っているなら、サーバーが許可しているか、そしてそのエンドポイントの正しいログイン形式を使っているかを確認してください。
  • 誤ったSQL認証情報

    • ユーザー名とパスワードを確認してください。
    • Azure SQLには、フルユーザー名をusername@servernameしてください。
  • ユーザーはデータベースに存在しません

    • ユーザーが指定されたデータベースにアクセスできるかどうかを確認しましょう。
    • サインインがデータベースユーザーに割り当てられているか確認してください。
  • 認証が設定されていません

    • Microsoft Entra認証(推奨):Authentication=ActiveDirectoryDefault
    • SQL認証を受け入れるはずのローカルSQL Serverのトラブルシューティングをしているなら、SQL Serverが混合モード認証を使っているか確認してください。

接続タイムアウト

症状:

OperationalError: [HYT00] (0) Timeout expired
OperationalError: [HYT01] (0) Connection timeout expired

考えられる原因と解決策:

  • サーバーの応答が遅い

    • 接続タイムアウトを延長する:
    conn = mssql_python.connect(connection_string, timeout=60)
    
  • ネットワーク待ち時間

    • サーバーへのネットワーク経路を確認してください。
    • 短いネットワークパスやVPNの使用を検討してみてください。
  • 重負荷下のサーバー

    • ピーク時間帯以外にも接続してみてください。
    • データベース管理者に連絡してください。

SSL 証明書エラー

症状:

OperationalError: [08001] SSL Provider: The certificate chain was issued by an authority that is not trusted

ソリューション:

まず、信頼できる証明書か コンテナおよびローカル開発のローカル開発パターンを優先してください。 TrustServerCertificate=yesは自分が管理するサーバーとのローカル開発にのみ使ってください。

自己署名証明書を使った開発およびテストの場合:

conn = mssql_python.connect(
    "Server=<server>.database.windows.net;"
    "Database=<database>;"
    "Authentication=ActiveDirectoryDefault;"
    "Encrypt=yes;"
    "TrustServerCertificate=yes;"  # Don't use in production
)

Caution

TrustServerCertificate=yes はローカル限定の代替手段です。 共有開発コンテナやCIパイプライン、本番環境のデプロイメントには持ち込まないでください。 より広範な指針については、「 暗号化と証明書」を参照してください。

本番環境では、適切な証明書がインストールされていることを確認し、以下を使用してください:

conn = mssql_python.connect(
    "Server=<server>.database.windows.net;"
    "Database=<database>;"
    "Authentication=ActiveDirectoryDefault;"
    "Encrypt=yes;"
    "HostnameInCertificate=<server>.domain.com;"
)

クエリ実行の問題

テーブルまたはオブジェクトが見つからない

症状:

ProgrammingError: [42S02] (208) Invalid object name 'TableName'.

考えられる原因と解決策:

  • 間違ったデータベースコンテキスト

    # Ensure you're connected to the correct database
    cursor.execute("SELECT DB_NAME()")
    print(cursor.fetchone()[0])
    
  • スキーマは指定されていません

    # Use fully qualified name
    cursor.execute("SELECT * FROM dbo.TableName")
    
  • テーブルは存在しません

    # Check if table exists
    cursor.execute("""
         SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
         WHERE TABLE_NAME = 'TableName'
    """)
    

構文エラー

症状:

ProgrammingError: [42000] (102) Incorrect syntax near '...'.

ソリューション:

  1. まずSSMSでSQLをテスト して構文を検証してください

  2. 文字列エスケープのチェック - パラメータ付きクエリの使用:

    # Wrong - vulnerable to syntax issues and SQL injection
    cursor.execute(f"SELECT * FROM Production.Product WHERE Name = '{name}'")
    
    # Correct - use parameters
    cursor.execute("SELECT * FROM Production.Product WHERE Name = %(name)s", {"name": name})
    

パラメータ誤差

症状:

ProgrammingError: [07001] Wrong number of parameters

ソリューション:

  1. プレースホルダーやパラメータを数えてください 。それらは一致しなければなりません

  2. 適切なパラメータスタイルを選ぶ:

    # Qmark style - positional
    cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Name LIKE ?", (1, "Adjustable%"))
    print(cursor.fetchone())
    
    # Pyformat style - named
    cursor.execute("SELECT * FROM Production.Product WHERE ProductID = %(id)s AND Name LIKE %(name)s", {"id": 1, "name": "Adjustable%"})
    print(cursor.fetchone())
    

データ型の問題

日付時変換エラー

症状:

DataError: [22007] Invalid datetime format

ソリューション:

文字列の代わりにPythonのdatetimeオブジェクトを使う:

from datetime import datetime

cursor.execute("CREATE TABLE #Events (EventDate DATETIME)")

# Wrong - this raises an error for invalid dates
try:
    cursor.execute("INSERT INTO #Events (EventDate) VALUES (%(event_date)s)", {"event_date": "2024-13-45"})
except Exception as e:
    print(f"Expected error: {e}")

# Correct - use Python datetime objects
cursor.execute("INSERT INTO #Events (EventDate) VALUES (%(event_date)s)", {"event_date": datetime(2024, 3, 15)})
cursor.execute("SELECT EventDate FROM #Events")
print(cursor.fetchone())

十進精度の問題

症状:

数字は切り詰められたり、誤って丸められたりします。

ソリューション:

正確な数値表示には decimal.Decimal を使います:

from decimal import Decimal

cursor.execute("CREATE TABLE #PriceDemo (ListPrice DECIMAL(10,2))")
# Preserve full precision
cursor.execute(
    "INSERT INTO #PriceDemo (ListPrice) VALUES (%(list_price)s)",
    {"list_price": Decimal("19.99")}
)

Unicodeエンコーディングの問題点

症状:

特殊文字は乱れたりエラーを生んだりします。

ソリューション:

  1. データベース内のUnicodeデータにはNVARCHAR列を使います

  2. 文字列を直接パスします - ドライバーがエンコーディングを担当します:

    cursor.execute("CREATE TABLE #UnicodeDemo (Name NVARCHAR(50))")
    cursor.execute("INSERT INTO #UnicodeDemo (Name) VALUES (%(name)s)", {"name": "日本語"})
    cursor.execute("SELECT Name FROM #UnicodeDemo")
    print(cursor.fetchone())
    

パフォーマンスの問題

クエリ実行の遅さ

考えられる原因と解決策:

  • インデックスが欠けている場合:SSMSでクエリ実行計画を確認してください。

  • 大きな結果セット:fetchmany()ではなくfetchall()を使う:

    cursor.arraysize = 1000
    while True:
         rows = cursor.fetchmany()
         if not rows:
             break
         process_rows(rows)
    
  • 接続プーリング無効:プーリングを有効にする:

    import mssql_python
    mssql_python.pooling(max_size=20, idle_timeout=300)
    

大きな結果に対する記憶の問題

症状:

Pythonプロセスはメモリを使い果たします。

ソリューション:

  1. すべてをメモリに読み込む代わりにストリーム結果を出す:

    cursor.execute("SELECT * FROM LargeTable")
    for row in cursor:  # Iterates one row at a time
        process_row(row)
    
  2. サーバー側ページ設定の活用:

    page_size = 1000
    offset = 0
    while True:
        cursor.execute(
            "SELECT * FROM LargeTable ORDER BY ID "
            "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY",
            (offset, page_size)
        )
        rows = cursor.fetchall()
        if not rows:
            break
        process_rows(rows)
        offset += page_size
    

取引に関する問題

オートコミットによる一時テーブルのスコーピング

トランザクション内で作成された一時テーブル(#tablename)は、トランザクションがロールバックされると消えます。 オートコミットがオフ(デフォルト)である場合、これはよくある混乱の原因です:

conn = mssql_python.connect(connection_string)  # autocommit=False by default
cursor = conn.cursor()

cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")

# If the connection rolls back (explicit or on error), #TempData disappears
conn.rollback()

# This fails: Invalid object name '#TempData'
cursor.execute("SELECT * FROM #TempData")

修正: 一時テーブルを作成したらすぐにコミットするか、オートコミットモードを使います:

cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()  # Lock in the table definition

cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()

CREATE DATABASEのように自動コミットモードが必要なDDL文は、オープントランザクション内で失敗します。 実行前にオートコミットを設定してください:

conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False

トランザクションはコミットされていません

症状:

接続を閉じた後もデータ変更は永続しません。

Solution:

autocommit=False(デフォルト)の場合、commit()と呼ぶ必要があります:

cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute("INSERT INTO #Products (Name) VALUES (%(name)s)", {"name": "Widget"})
conn.commit()  # Don't forget this!

またはオートコミットモードを使うこともできます:

conn = mssql_python.connect(connection_string, autocommit=True)

デッドロック エラー

症状:

OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process

Solution:

リトライロジック(リ トライロジックを参照)は即時の故障を処理しますが、繰り返されるデッドロックは設計上の問題を示しています。 根本原因を解決するために、デッドロックグラフを取得し、関与している文やロックの種類を分析します。 一般的な修正には、競合するトランザクションが同じ順序でロックを取得するように操作を並べ替えること、トランザクション範囲の縮小、ロック持続時間を短縮するための適切なインデックスの追加などがあります。

デッドロック解析の詳細な解説については 、Deadlocksガイドをご覧ください。 Azure SQL Databaseを使用している場合は、「Analyze and prevent deadlocks」をご覧ください。

一括読み込みの問題

バルクコピー中の制約違反

症状:

RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint

原因:

バッチ内のデータはテーブルの制約(プライマリキー、ユニーク、CHECK、または外部キー)に違反します。

修正:

読み込み前にデータを検証してください。 大規模なデータセットの場合は、まずステージングテーブルにロードし、その後ターゲットにマージします:

# Load into staging, then validate
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(100))")
cursor.bulkcopy("##Staging", rows)

# Check for duplicates before merging
cursor.execute("""
    SELECT s.ID FROM ##Staging s
    INNER JOIN dbo.Target t ON s.ID = t.ID
""")
dupes = cursor.fetchall()
if dupes:
    print(f"Skipping {len(dupes)} duplicate rows")

# Insert only non-duplicate rows
cursor.execute("""
    INSERT INTO dbo.Target (ID, Name)
    SELECT s.ID, s.Name FROM ##Staging s
    WHERE NOT EXISTS (SELECT 1 FROM dbo.Target t WHERE t.ID = s.ID)
""")
conn.commit()

ステージングテーブル付きのアップサートパターンについては、 データロードおよび移動パターンを参照してください。

列マッピング エラー

症状:

RuntimeError: Bulk copy failure - column count mismatch

原因:

データの列数がターゲットテーブルの列数と合っていなかったり、列の順番が間違っている場合もあります。

修正:

データがテーブルスキーマと正確に一致し、順序と数を揃えていることを確認してください:

# Check the target table schema
cursor.execute("""
    SELECT COLUMN_NAME, DATA_TYPE
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME = 'MyTable'
    ORDER BY ORDINAL_POSITION
""")
for col in cursor.fetchall():
    print(col)

# Match your data to the column order
rows = [
    (1, "Widget", Decimal("19.99")),  # Must match table column order
    (2, "Gadget", Decimal("29.99")),
]
cursor.bulkcopy("dbo.MyTable", rows)

一括コピー時のタイプミスマッチ

症状:

データは読み込まれますが、値が切り捨てられたり、丸められたり、正しくありません。

原因:

Pythonの値はターゲットのカラムタイプにきれいにマッピングされません。 一般的なケース:float列に読み込まれたdecimal値(精度損失)、または固定長の列に読み込まれる過大文字列。

修正:

スキーマに合った正しいPython型を使いましょう:

from decimal import Decimal

# Use Decimal for decimal/numeric columns, not float
rows = [
    (1, "Widget", Decimal("19.99")),  # Correct
    # (1, "Widget", 19.99),           # Avoid: float loses precision
]
cursor.bulkcopy("dbo.Products", rows)

NumPy型バインディングエラー

症状:

numpy整数型やfloat型を使用すると、パラメータは静かに失敗したりデータ型エラーを引き起こしたりします。

原因:

NumPy 2.x では、numpy.int64numpy.int32 のような NumPy の型は isinstance(x, int) を通りません。 ドライバーの型推論がそれらを認識せず、予期せぬ挙動を引き起こします。

修正:

バインディング前にnumpyの値をネイティブPython型に変換してください:

import numpy as np

# Convert individual values
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = %(product_id)s", {"product_id": int(np.int64(42))})

# Convert DataFrame values
for _, row in df.iterrows():
    cursor.execute(
        "INSERT INTO #Orders (ProductID, Qty) VALUES (%(product_id)s, %(qty)s)",
        {"product_id": int(row["ProductID"]), "qty": int(row["Qty"])}
    )

大規模なデータセットの場合は、内部で型変換を処理する Arrowpandas の統合パスを使いましょう。

一時テーブル付きのバルクコピー

症状:

cursor.bulkcopy("#TempTable", data)RuntimeError: Invalid object name '#TempTable'を発生させます。

原因:

bulkcopy() メタデータの検索制限によりセッション一時テーブル(#tablename)を解決できません。 グローバル一時テーブル(##tablename)と常設テーブルは動作します。

修正:

グローバル温度表または通常のステージング表を使いましょう:

# Global temp table (visible to all sessions, dropped when last session disconnects)
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("##Staging", rows)

# Or use a permanent staging table
cursor.execute("CREATE TABLE dbo.Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("dbo.Staging", rows)

セッション一時テーブルが好まれる小規模データセットでは、代わりに executemany() を使いましょう:

cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany("INSERT INTO #Staging (ID, Name) VALUES (?, ?)", rows)

コンテナおよびCIの問題

Linuxにおける欠落したシステムライブラリ

症状:

ImportError: libltdl.so.7: cannot open shared object file: No such file or directory
ImportError: libkrb5.so.3: cannot open shared object file

修正:

必要なシステムパッケージをインストールしてください。 パッケージはディストリビューションによって異なります:

Distribution インストール コマンド
Ubuntu/Debian sudo apt-get install libltdl7 libkrb5-3 libgssapi-krb5-2
レッドハット / フェドラ sudo dnf install libtool-ltdl krb5-libs
アルパイン apk add libltdl krb5-libs

Dockerfileの例については、 コンテナおよびローカル開発を参照してください。

インストール後のmacOS SSLエラー

症状:

macOSから接続する際、特にApple Silicon上でSSL関連のエラーが発生します。

修正:

Homebrew経由でOpenSSLをインストールし、リンカーフラグを設定してください:

brew install openssl
export LDFLAGS="-L/opt/homebrew/opt/openssl/lib"
export CPPFLAGS="-I/opt/homebrew/opt/openssl/include"

診断ツール

ドライバーログを有効にする

トラブルシューティングのために包括的なDEBUGログを有効にするために mssql_python.setup_logging() を活用しましょう。 すべてのドライバ操作はログに記録され、SQL文、パラメータ、内部ODBC操作、接続状態の変更が含まれます。

import mssql_python

# Enable logging to file (default)
mssql_python.setup_logging()

# Output to stdout (useful for CI/CD and containers)
mssql_python.setup_logging(output='stdout')

# Output to both file and stdout
mssql_python.setup_logging(output='both')

# Custom log file path (must use .txt, .log, or .csv extension)
mssql_python.setup_logging(log_file_path="/var/log/myapp/mssql.log")

ログファイルはCSV形式で書かれ、512MBで自動的に回転し、5つのバックアップがあります。 パスワードやアクセストークンなどの機密データはログ出力で自動的にサニティ化されます。

ドライバーログに加えて自分のログを追加するには、 driver_loggerをご利用ください:

from mssql_python.logging import driver_logger

mssql_python.setup_logging()

driver_logger.debug("[App] Starting data processing")
driver_logger.error("[App] Failed to process record")
# Your entries appear in the same file with the same format

Caution

ログ記録にはパフォーマンス上のオーバーヘッドがあります。 トラブルシューティング時のみ有効にし、本番環境ではデフォルトで有効にしないでください。

ドライバー情報を取得する

アクティブな接続からドライバーのバージョンとサーバー情報を取得する:

import mssql_python

conn = mssql_python.connect(connection_string)

# Driver version
print(f"Version: {mssql_python.__version__}")

# Server information
print(f"Server name: {conn.getinfo(mssql_python.SQL_SERVER_NAME)}")
print(f"Database name: {conn.getinfo(mssql_python.SQL_DATABASE_NAME)}")

接続の状態を確認する

操作を試みる前に接続がまだ開いているかをテストしてください:

try:
    cursor = conn.cursor()
    cursor.execute("SELECT 1")
    print("Connection is open")
except mssql_python.Error:
    print("Connection is closed or broken")

クイックリファレンス:よくある誤り

エラー SQLSTATE 一般的な原因 クイック修復
クライアントが接続を確立できない 08001 サーバーに到達できない サーバー名やポートを確認してください
ログインに失敗しました 28000 誤った資格 ユーザー名とパスワードを確認してください
タイムアウトの期限が切れました HYT00/HYT01 スローネットワーク タイムアウトを増やす
無効なオブジェクト名 42S02 間違ったテーブル/スキーマ 完全修飾名を使用してください
構文エラー 42000 SQL エラー パラメーター化されたクエリを使用する
制約違反 23000 FK/PK違反 データの整合性をチェック
デッドロック 40001 ロックの競合 再試行してからデッドロックグラフを解析します