Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Используйте эту статью для диагностики проблем с выполнением запросов, типом данных, производительностью, транзакциями и массовым копированием драйвера 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