{"meta":{"title":"データベースのデッドロックまたはデータ整合性の問題の解決","intro":"Copilot Chat は、データベース操作が遅くなったりブロックされたりするコードや、データが見つからない、または正しくないテーブルを回避するのに役立ちます。","product":"GitHub Copilot","breadcrumbs":[{"href":"/ja/copilot","title":"GitHub Copilot"},{"href":"/ja/copilot/tutorials","title":"チュートリアル"},{"href":"/ja/copilot/tutorials/copilot-cookbook","title":"GitHub Copilot クックブック"},{"href":"/ja/copilot/tutorials/copilot-cookbook/refactor-code","title":"コードのリファクタリング"},{"href":"/ja/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\n2 つ以上のトランザクションがデータベース テーブル内の同じ行を、異なる順序で更新しようとすると、循環待機状態が発生する可能性があります。\n\n### サンプル シナリオ\n\n次の SQL スニペットでは、テーブルの 1 つの行が更新されてから、数秒かかる操作が実行された後、同じテーブルの別の行が更新されます。 これは、トランザクションが `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**アクセスの順序：** すべてのトランザクションがテーブルと行に同じ順序でアクセスしていることを確認します。\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` のさまざまな条件を満たす行から、一部のフィールドのデータが格納されます。\n`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* **バッチ処理:** 1 つの大きなトランザクションではなく、小さなバッチでデータを処理します。 これは、制限とオフセットを持つ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 は、エラー処理を伴うトランザクションを使用してこれを実現することを示します。 SQL Serverの `TRY...CATCH` コンストラクトを使用した次の例を示します。\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 のプロンプト エンジニアリング](/ja/copilot/concepts/prompting/prompt-engineering)\n* [GitHub Copilot の使用に関するベスト プラクティス](/ja/copilot/get-started/best-practices)"}