Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Используйте эту статью для диагностики проблем с выполнением запросов, типом данных, производительностью, транзакциями и массовым копированием драйвера mssql-python .
Проблемы с выполнением запросов
Таблица или объект не найден.
Симптомы:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Возможные причины и решения:
Некорректный контекст базы данных
cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Схема не указана
cursor.execute("SELECT * FROM dbo.TableName")Таблицы не существует
cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Синтаксическая ошибка
Симптомы:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Решения:
Проверьте инструкцию SQL в SQL Server Management Studio (SSMS), чтобы убедиться в правильности синтаксиса.
Используйте параметризованный запрос вместо интерполяции строк:
# Don't use string interpolation for query parameters. cursor.execute(f"SELECT * FROM Production.Product WHERE Name = '{name}'") # Use parameters. cursor.execute( "SELECT * FROM Production.Product WHERE Name = %(name)s", {"name": name}, )
Ошибки параметров
Симптомы:
ProgrammingError: [07001] Wrong number of parameters
Решения:
Посчитайте заполнители и параметры. Счёты должны совпадать.
Выберите правильный стиль параметра:
# Qmark style: positional parameters cursor.execute( "SELECT * FROM Production.Product " "WHERE ProductID = ? AND Name LIKE ?", (1, "Adjustable%"), ) print(cursor.fetchone()) # Pyformat style: named parameters 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
Solution:
Используйте объекты Python datetime вместо строк.
from datetime import datetime
cursor.execute("CREATE TABLE #Events (EventDate DATETIME)")
# This value raises an error because the date is invalid.
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}")
# Use a Python datetime object.
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())
Проблемы с десятичной точностью
Симптомы:
Числа выглядят усечёнными или округлёнными неправильно.
Solution:
Использование decimal.Decimal для точных числовых значений:
from decimal import Decimal
cursor.execute("CREATE TABLE #PriceDemo (ListPrice DECIMAL(10, 2))")
cursor.execute(
"INSERT INTO #PriceDemo (ListPrice) VALUES (%(list_price)s)",
{"list_price": Decimal("19.99")},
)
Проблемы с кодированием Unicode
Симптомы:
Особые символы выглядят искажёнными или вызывают ошибки.
Решения:
Используйте столбцы nvarchar для данных Unicode в вашей базе данных.
Передавайте строки непосредственно. Драйвер занимается кодированием:
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 не хватает памяти.
Решения:
Передавайте результаты потоком вместо загрузки всех строк в память.
cursor.execute("SELECT * FROM LargeTable") for row in cursor: process_row(row)Используйте серверную пагинацию.
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)
cursor = conn.cursor()
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
# An explicit rollback or an error removes #TempData.
conn.rollback()
# This statement fails with "Invalid object name '#TempData'".
cursor.execute("SELECT * FROM #TempData")
Сделайте коммит сразу после создания временной таблицы или используйте режим автокоммита:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit()
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()
DDL-операторы, требующие режима автофиксации, например CREATE DATABASE, не работают внутри открытой транзакции. Включите автокоммит перед тем, как запускать их:
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()
Или используйте режим автоподтверждения:
conn = mssql_python.connect(connection_string, autocommit=True)
Ошибки взаимоблокировки
Симптомы:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Solution:
Повторная логика решает немедленный сбой, но повторяющиеся тупики указывают на конструктивную проблему. Соберите граф взаимоблокировок и проанализируйте инструкции и типы блокировок. Распространённые исправления включают следующие изменения:
- Измените порядок операций так, чтобы конкурирующие транзакции получали блокировки в одной и той же последовательности.
- Сократьте объем транзакций.
- Добавьте соответствующие индексы, чтобы сократить время блокировки.
Для полного обзора анализа тупиков смотрите руководство по Deadlocks. Если вы используете База данных SQL Azure, см. Анализ и предотвращение взаимоблокировок.
Проблемы с массовой нагрузкой
Нарушения ограничений во время массового копирования
Симптомы:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Причина:
Данные в вашей партии нарушают ограничения таблицы, такие как ограничения первичного ключа, уникального, проверочного или внешнего ключа.
Solution:
Проверьте данные перед загрузкой. Для больших наборов данных загрузите данные в промежуточную таблицу, а затем объедините их с целевой таблицей:
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(100))")
cursor.bulkcopy("##Staging", rows)
# Check for duplicate rows before the merge.
cursor.execute("""
SELECT s.ID
FROM ##Staging AS s
INNER JOIN dbo.Target AS t
ON s.ID = t.ID
""")
dupes = cursor.fetchall()
if dupes:
print(f"Skipping {len(dupes)} duplicate rows")
# Insert rows that don't exist in the target.
cursor.execute("""
INSERT INTO dbo.Target (ID, Name)
SELECT s.ID, s.Name
FROM ##Staging AS s
WHERE NOT EXISTS (
SELECT 1
FROM dbo.Target AS t
WHERE t.ID = s.ID
)
""")
conn.commit()
Для сценариев upsert с промежуточными таблицами см. Шаблоны загрузки и перемещения данных.
Ошибки отображения столбцов
Симптомы:
RuntimeError: Bulk copy failure - column count mismatch
Причина:
Количество столбцов в ваших данных не совпадает с количеством столбцов целевой таблицы или столбцы расположены в неправильном порядке.
Solution:
Убедитесь, что ваши данные соответствуют схеме таблицы по порядку столбцов и их количеству:
from decimal import Decimal
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)
rows = [
(1, "Widget", Decimal("19.99")),
(2, "Gadget", Decimal("29.99")),
]
cursor.bulkcopy("dbo.MyTable", rows)
Несоответствия типов при массовом копировании
Симптомы:
Данные загружаются, но значения усечаны, округлены или некорректны.
Причина:
Значения Python не могут быть однозначно сопоставлены с типами целевого столбца. Распространённые примеры включают float значения, загруженные в десятичные столбцы, что может терять точность, а также увеличенные строки, загруженные в столбцы фиксированной длины.
Solution:
Используйте типы Python, соответствующие вашей схеме:
from decimal import Decimal
rows = [
# Use Decimal for decimal and numeric columns.
(1, "Widget", Decimal("19.99")),
# Avoid float values because they can lose precision.
# (1, "Widget", 19.99),
]
cursor.bulkcopy("dbo.Products", rows)
Сбои связывания типа NumPy
Симптомы:
Параметры тихо сбывают или вызывают ошибки типов данных, когда вы используете целочисленные или плавающие типы NumPy.
Причина:
Типы NumPy, такие как numpy.int64 и numpy.int32, не проходят проверку isinstance(x, int) в NumPy 2.x. Механизм вывода типов драйвера не распознаёт их, из-за чего возникает непредсказуемое поведение.
Solution:
Преобразуйте значения NumPy в родные типы Python перед тем, как их привязать:
import numpy as np
cursor.execute(
"SELECT * FROM Production.Product WHERE ProductID = %(product_id)s",
{"product_id": int(np.int64(42))},
)
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"]),
},
)
Для больших наборов данных используйте пути интеграции Arrow или pandas . Эти пути обеспечивают внутреннее преобразование типов.
Массовое копирование с временными таблицами
Симптомы:
cursor.bulkcopy("#TempTable", data) вызывает RuntimeError: Invalid object name '#TempTable'.
Причина:
bulkcopy() Не могу разрешить временные таблицы сессий (#tablename) из-за ограничений поиска метаданных. Глобальные временные таблицы (##tablename) и постоянные таблицы работают.
Solution:
Используйте глобальную временную таблицу или обычную таблицу стадирования:
# A global temp table is visible to all sessions and is dropped
# when the last session disconnects.
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("##Staging", rows)
# Alternatively, 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,
)
Связанные материалы
- Выполняйте запросы с помощью mssql-python
- Отображения типов данных с помощью mssql-python
- Управление транзакциями с помощью mssql-python
- Настройка производительности с помощью mssql-python
- Массовое копирование с помощью mssql-python
- Обработка ошибок и коды SQLSTATE для mssql-python
- Устранение неполадок mssql-python