{"meta":{"title":"Устранение проблем с взаимоблокировкой базы данных или целостности данных","intro":"Copilot Chat Это поможет избежать кода, вызывающего медленные или заблокированные операции базы данных, или таблицы с отсутствующими или неправильными данными.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ru/copilot","title":"GitHub Copilot"},{"href":"/ru/copilot/tutorials","title":"Учебники"},{"href":"/ru/copilot/tutorials/copilot-cookbook","title":"Кулинарная книга GitHub Copilot"},{"href":"/ru/copilot/tutorials/copilot-cookbook/refactor-code","title":"Код рефакторинга"},{"href":"/ru/copilot/tutorials/copilot-cookbook/refactor-code/fix-database-deadlocks","title":"Устранение взаимоблокировок базы данных"}],"documentType":"article"},"body":"# Устранение проблем с взаимоблокировкой базы данных или целостности данных\n\nCopilot Chat Это поможет избежать кода, вызывающего медленные или заблокированные операции базы данных, или таблицы с отсутствующими или неправильными данными.\n\nСложные операции базы данных, особенно связанные с транзакциями, могут привести к взаимоблокировкам или несоответствиям данных, которые трудно отлаживать.\n\nCopilot Chat Может помочь выявить точки в транзакции, где может возникнуть блокировка или тупик, а также предложить лучшие практики по изоляции транзакций или их разрешению, например, корректируя стратегии блокировки или аккуратное обращение с исключениями из тупиков.\n\n> \\[!NOTE] Ответы, показанные в этой статье, являются примерами.\n> Copilot Chat Ответы не детерминированы, поэтому вы можете получить другие ответы, чем показаны здесь.\n\n## Избегайте одновременных обновлений между строками\n\nЕсли две или более транзакций пытаются обновить одни и те же строки в таблице базы данных, но в разных заказах, это может привести к циклическим условию ожидания.\n\n### Пример сценария\n\nСледующий фрагмент КОДА SQL обновляет одну строку таблицы, а затем выполняет операцию, которая занимает несколько секунд, а затем обновляет другую строку в той же таблице. Это проблематично, так как транзакция блокирует `id = 1` строку в течение нескольких секунд до завершения транзакции, освобождая блокировку. Если другая транзакция начинается в течение этого времени, которая выполняет аналогичную операцию, но блокирует `id = 2` строку первым, чтобы она может обновить строку, а затем пытается заблокировать `id = 1` строку, обе транзакции останутся в ожидании завершения другой, что приведет к взаимоблокировке.\n\n```sql id=deadlock-example\nBEGIN TRANSACTION;\nUPDATE my_table SET value = 'Some value' WHERE id = 301;\n-- Simulate a process taking 5 seconds:\nWAITFOR DELAY '00:00:05';\nUPDATE my_table SET value = 'Another value' WHERE id = 127;\nCOMMIT TRANSACTION;\n```\n\n### Пример запроса 1\n\nВы можете проверить наличие проблем с этой транзакцией.\n\nВ редакторе выберите код транзакции, затем спросите Copilot Chat:\n\n```copilot copy prompt ref=deadlock-example\nIs this transaction good?\n```\n\n### Пример ответа 1\n\nCopilot Он говорит, что «транзакция в вашем SQL-коде в целом в порядке», но перечисляет некоторые моменты, которые стоит учитывать: длительность блокировки, обработка ошибок и параллельность. В нем упоминается, что \"транзакция держит блокировки в течение длительного периода, что потенциально приводит к блокировке или взаимоблокировкам\". Ответ также содержит измененный код, который добавляет обработку ошибок.\n\nВ этом случае вы решили не добавлять обработку ошибок. Сейчас вы хотите устранить потенциал взаимоблокировок.\n\n### Пример запроса 2\n\nВведите следующий запрос:\n\n```copilot copy prompt ref=deadlock-example\nHow can I rewrite this code to reduce the chance of deadlock to a minimum while not adversely affecting performance. Tell me anything else I can do to avoid a deadlock. Note: I don't want to add error handling at this time.\n```\n\n### Пример ответа 2\n\nCopilot Даёт следующие советы:\n\n> *\n\n**Порядок Access:** Убедитесь, что все транзакции access таблицы и строки в одном порядке.\n\n> \\*\n> **Сохранение коротких транзакций.** Свести к минимуму время, когда транзакция удерживает блокировки.\n> \\*\n> **Используйте соответствующие уровни изоляции:** используйте самый низкий уровень изоляции, соответствующий вашим требованиям.\n>\n> Ниже приведена обновленная версия кода:\n\n```sql\nBEGIN TRANSACTION;\n-- Update the rows in a consistent order\nUPDATE my_table SET value = 'Another value' WHERE id = 127;\nUPDATE my_table SET value = 'Some value' WHERE id = 301;\n-- Simulate a process taking 5 seconds:\nWAITFOR DELAY '00:00:05';\nCOMMIT TRANSACTION;\n```\n\n## Избегайте поиска без индекса\n\nПоиск столбцов таблицы, не индексированных, обычно приводит к полной проверке таблицы. Это может быть очень медленным и ресурсоемким, что повышает вероятность узких мест производительности.\n\n### Пример сценария\n\nСледующий SQL приведет к полной проверке таблицы, если `some_column` не индексируется:\n\n```sql id=full-table-scan\nBEGIN TRANSACTION;\nSELECT * FROM my_table WHERE some_column = 'some_value';\n-- More actions here, then:\nCOMMIT TRANSACTION;\n```\n\n### Пример запроса\n\nЗадавая Copilot следующий вопрос, обычно выявляя потенциальную проблему.\n\n```copilot copy prompt ref=full-table-scan\nHow can I optimize this transaction?\n```\n\n### Пример ответа\n\nCopilot Даёт некоторые советы и упоминает, что колонка должна быть индексирована:\n\n> Чтобы оптимизировать транзакцию, необходимо убедиться, что транзакция максимально коротка, чтобы уменьшить блокировку и повысить производительность. Ниже приведены несколько советов.\n>\n> 1.\n\n**Свести к минимуму работу, выполняемую в транзакции:** в транзакцию включаются только необходимые операции.\n\n> 1\\.\n> **Используйте соответствующие индексы:** убедитесь, что столбцы, используемые в предложении WHERE, индексируются.\n> 1\\.\n> **Избегайте длительных транзакций:** не закрывайте длительность транзакции, чтобы избежать проблем с блокировкой.\n\nПредлагаемый код в ответе включает команду SQL для индексирования столбца:\n\n```sql\n`CREATE INDEX idx_some_column ON my_table(some_column);`\n```\n\n## Предотвращение длительных транзакций\n\nВажно избежать длительных запросов и транзакций, когда это возможно, так как они могут значительно снизить производительность и вызвать узкие места для других операций. Кроме того, они могут использовать значительные объемы памяти и пространства журналов, что делает приложение более подверженным сбою в средах с высокой нагрузкой.\n\n### Пример сценария\n\nВ следующем SQL создаются новые строки `target_table`, содержащие данные из выбранных полей строк, в `source_table` которых выполняются различные условия. Если `source_table` это очень большой, это может привести к длительной транзакции.\n\n```sql id=long-running-transaction\nBEGIN TRANSACTION;\n\nINSERT INTO target_table (first_name, last_name, email, dept, role, hire_date)\nSELECT first_name, last_name, email, department, job_title, start_date\nFROM source_table\nWHERE (department = 'Engineering' AND (salary > 95000 OR grade > 5))\n  OR (department = 'Marketing' AND performance_rating = 'Excellent');\n\nCOMMIT;\n```\n\n### Пример запроса\n\nМожно спросить Copilot , возможно ли избежать долгосрочных транзакций.\n\n```copilot copy prompt ref=long-running-transaction\nsource_table is an extremely large table. Without altering the table, how can I ensure this SQL doesn't become a long-running query, that blocks other operations?\n```\n\n### Пример ответа\n\nCopilot Предлагают следующие стратегии:\n\n* **Пакетная обработка.** Обработка данных в небольших пакетах вместо одной большой транзакции. Это можно сделать с помощью loop с пределом и смещением.\n* **Индексирование.** Убедитесь, что столбцы, используемые в `WHERE` предложении (`department`, , `salary``grade`и`performance_rating`) индексируются для ускорения запроса.\n* **Блокировка:** используйте блокировку на уровне строк, чтобы избежать блокировки всей таблицы.\n\nОн предоставляет следующий пример реализации пакетной обработки. Этот SQL обрабатывает данные в пакетах из 1000 строк за раз, уменьшая нагрузку на базу данных и предотвращая длительные транзакции.\n\n```sql\nDECLARE @BatchSize INT = 1000;\nDECLARE @Offset INT = 0;\nDECLARE @RowCount INT;\n\nSET @RowCount = @BatchSize;\n\nWHILE @RowCount = @BatchSize\nBEGIN\n    BEGIN TRANSACTION;\n\n    INSERT INTO target_table (first_name, last_name, email, dept, role, hire_date)\n    SELECT first_name, last_name, email, department, job_title, start_date\n    FROM source_table\n    WHERE (department = 'Engineering' AND salary > 95000)\n       OR (department = 'Engineering' AND years_of_experience > 5)\n       OR (department = 'Marketing' AND performance_rating = 'Excellent');\n    ORDER BY primary_key_column\n    OFFSET @Offset ROWS FETCH NEXT @BatchSize ROWS ONLY;\n\n    SET @RowCount = @@ROWCOUNT;\n    SET @Offset = @Offset + @BatchSize;\n\n    COMMIT;\nEND;\n```\n\nCopilot предлагает заменить `primary_key_column` в предложенном коде имя фактического столбца первичного ключа `source_table`.\n\n## Избегайте проблем с целостностью данных\n\nВажно, чтобы информация в базах данных оставалась точной, согласованной и полной. Плохо разработанные запросы могут привести к отсутствием или неправильным данным.\n\n### Пример сценария\n\nСледующая транзакция SQL удаляет запись сотрудника и создает журнал удаления. Тем не менее, операция может `DELETE` завершиться успешно, и `INSERT` операция завершится ошибкой, в этом случае для удаления нет записи журнала.\n\n```sql id=delete-employee\nBEGIN TRANSACTION;\n\nDELETE FROM employees\nWHERE employee_id = 101;\n\nINSERT INTO deletion_log (employee_id, deletion_date, reason)\nVALUES (101, GETDATE(), 'Voluntary Resignation');\n\nCOMMIT TRANSACTION;\n```\n\n### Пример запроса\n\n```copilot copy prompt ref=delete-employee\nHow can I ensure that the DELETE and INSERT operations are only performed if both succeed?\n```\n\n### Пример ответа\n\nCopilot сообщает, что вы достигаете этого с помощью транзакции с обработкой ошибок. Приводится следующий пример с использованием конструкции `TRY...CATCH` SQL Server:\n\n```sql\nBEGIN TRY\n    BEGIN TRANSACTION;\n\n    DELETE FROM employees\n    WHERE employee_id = 101;\n\n    INSERT INTO deletion_log (employee_id, deletion_date, reason)\n    VALUES (101, GETDATE(), 'Voluntary Resignation');\n\n    COMMIT TRANSACTION;\nEND TRY\nBEGIN CATCH\n    ROLLBACK TRANSACTION;\n    -- Handle the error, e.g., log it or re-throw\n    DECLARE @ErrorMessage NVARCHAR(4000);\n    DECLARE @ErrorSeverity INT;\n    DECLARE @ErrorState INT;\n\n    SELECT\n        @ErrorMessage = ERROR_MESSAGE(),\n        @ErrorSeverity = ERROR_SEVERITY(),\n        @ErrorState = ERROR_STATE();\n\n    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);\nEND CATCH;\n```\n\nПредлагаемый код гарантирует, что `DELETE` при сбое или `INSERT` операции транзакция выполняется откат и никаких изменений в базе данных не выполняется.\n\n## Дополнительные материалы\n\n* [Инженерия подсказок для GitHub Copilot Chat](/ru/copilot/concepts/prompting/prompt-engineering)\n* [Лучшие практики использования GitHub Copilot](/ru/copilot/get-started/best-practices)"}