リレーショナルデータベースでは、さまざまな形式でデータを格納するためのテーブルを作成します。 SQL Serverは、各データ型に関連付けられた値を保持する行と列の形式でデータを格納します。 SQLテーブルを設計するときは、整数、浮動小数点、10進数、varchar、ビットなどのデータ型を定義します。たとえば、顧客データを格納するテーブルには、顧客名、電子メール、住所、州、国などのフィールドが含まれる場合があります。さまざまなSQLコマンドがSQLテーブルで実行され、次のカテゴリに分類できます。
- データ定義言語(DDL): これらのコマンドは、データベース内のデータベースオブジェクトを作成および変更するために使用されます。
- 作成: オブジェクトを作成します
- 変更: オブジェクトを変更します
- ドロップ: オブジェクトを削除します
- 切り捨て: テーブルからすべてのデータを削除します
- データ操作言語(DML): これらのコマンドは、データベース内のデータを挿入、取得、変更、削除、および更新します。
- 選択: 単一または複数のテーブルからデータを取得します
- 挿入: テーブルに新しいデータを追加します
- 更新: 既存のデータを変更する
- 削除: テーブル内の既存のレコードを削除します
- データ制御言語(DCL): これらのコマンドは、データベース内の権限または権限制御に関連付けられています。
- 付与: ユーザーに権限を割り当てます
- 取り消し: ユーザーから権限を取り消します
- トランザクション制御言語(TCL): これらのコマンドは、データベース内のトランザクションを制御します。
- コミット: クエリによって行われた変更を保存します
- ロールバック: 明示的または暗黙的なトランザクションをトランザクションの開始、またはトランザクション内のセーブポイントにロールバックします
- トランザクションを保存する: トランザクション内にセーブポイントまたはマーカーを設定します
SQLテーブルに顧客注文データが保存されているとします。このテーブルにデータを継続的に挿入し続けると、テーブルに数百万のレコードが含まれる可能性があり、アプリケーション内でパフォーマンスの問題が発生する可能性があります。インデックスのメンテナンスにも非常に時間がかかる場合があります。多くの場合、3年以上経過した注文を保持する必要はありません。このような場合、それらのレコードをテーブルから削除できます。これにより、ストレージスペースが節約されるだけでなく、メンテナンスの労力も軽減されます。
SQLテーブルからデータを削除するには、次の2つの方法があります。
- SQL削除ステートメントの使用
- 切り捨ての使用
これらのSQLコマンドの違いについては後で説明します。まず、SQLの削除ステートメントについて見ていきましょう。
条件のないSQL削除ステートメント
データ操作言語(DML)ステートメントでは、SQLdeleteステートメントがテーブルから行を削除します。特定の行またはすべての行を削除できます。基本的な削除ステートメントには引数は必要ありません。
以下のスクリプトを使用して、OrdersSQLテーブルを作成しましょう。このテーブルには、[OrderID]、[ProductName]、[ProductQuantity]の3つの列があります。
Create Table Orders
( OrderID int,
ProductName varchar(50),
ProductQuantity int
)
このテーブルにいくつかのレコードを挿入します。
Insert into Orders values (1,'ABC books',10),
(2,'XYZ',100),
(3,'SQL book',50)
ここで、テーブルデータを削除するとします。削除ステートメントを使用して、データを削除するテーブル名を指定できます。両方のSQLステートメントは同じです。 (オプション)キーワードからテーブル名を指定することも、削除直後にテーブル名を指定することもできます。
Delete Orders
Go
Delete from Orders
GO
フィルタリングされたデータを含むSQL削除ステートメント
これらのSQL削除ステートメントは、すべてのテーブルのデータを削除します。通常、SQLテーブルからすべての行を削除するわけではありません。特定の行を削除するには、deleteステートメントを使用してwhere句を追加します。 where句にはフィルター基準が含まれ、最終的に削除する行を決定します。
たとえば、注文ID 1を削除するとします。where句を追加すると、SQL Serverは最初に対応する行をチェックし、それらの特定の行を削除します。
Delete Orders where orderid=1
where句の条件がfalseの場合、行は削除されません。たとえば、ordered1をordersテーブルから削除しました。ステートメントを再度実行すると、where句の条件を満たす行が見つかりません。この場合、影響を受けた0行を返します。
SQL削除ステートメントとTOP句
TOPステートメントを使用して、行を削除することもできます。たとえば、次のクエリは、Ordersテーブルから上位100行を削除します。
Delete top (100) [OrderID]
from Orders
「ORDERBY」を指定していないため、ランダムな行を選択して削除します。 Order by句を使用して、データを並べ替え、一番上の行を削除できます。以下のクエリでは、[OrderID]を降順で並べ替えてから、[Orders]テーブルから削除します。
Delete from Orders where [OrderID] In
(
Select top 100 [OrderID] FROM Orders
order by [OrderID] Desc
)
別のテーブルに基づいて行を削除する
別のテーブルに基づいて行を削除する必要がある場合があります。このテーブルは同じデータベースに存在する場合と存在しない場合があります。
- テーブルルックアップ
テーブルルックアップメソッドまたはSQL結合を使用して、これらの行を削除できます。たとえば、次の条件を満たす[Orders]テーブルから行を削除するとします。
[dbo]。[Customer]テーブルに対応する行が必要です。
以下のクエリを見てください。ここでは、deleteステートメントのwhere句にselectステートメントがあります。 SQL Serverは、最初にselectステートメントを満たす行を取得し、次にSQLdeleteステートメントを使用して[Orders]テーブルからそれらの行を削除します。
Delete Orders where orderid in
(Select orderid
from Customer)
- SQL結合
または、これらのテーブル間でSQL結合を使用して、行を削除することもできます。以下のクエリでは、テーブル[Orders]]を[Customer]テーブルと結合します。 SQL結合は、常にテーブル間の共通の列で機能します。両方のテーブルを結合する列[OrderID]があります。
DELETE Orders
FROM Orders o
INNER JOIN Customer c ON o.orderid=c.orderid
上記の削除ステートメントを理解するために、実際の実行プランを見てみましょう。
実行プランに従って、両方のテーブルでテーブルスキャンを実行し、一致するデータを取得して、それらをOrdersテーブルから削除します。
- 共通テーブル式(CTE)
Common Table Expression(CTE)を使用して、SQLテーブルから行を削除することもできます。まず、削除する行を見つけるためにCTEを定義します。
次に、CTEをSQLテーブルOrdersと結合し、行を削除します。
WITH cteOrders AS
(SELECT OrderID
FROM Customer
WHERE CustomerID = 1 )
DELETE Orders
FROM cteOrders sp
INNER JOIN dbo.Orders o ON o.orderid = sp.orderid;
アイデンティティ範囲への影響
SQL ServerのID列は、列に対して一意の順次値を生成します。これらは主に、SQLテーブルの行を一意に識別するために使用されます。主キー列は、SQLServerのクラスター化インデックスにも適しています。
以下のスクリプトには、[Employee]テーブルがあります。このテーブルにはID列IDがあります。
Create Table Employee
(
id int identity(1,1),
[Name] varchar(50)
)
このテーブルに50個のレコードを挿入し、id列のID値を生成しました。
Declare @id int=1
While(@id<=50)
BEGIN
Insert into Employee([Name]) values('Test'+CONVERT(VARCHAR,@ID))
Set @id=@id+1
END
SQLテーブルからいくつかの行を削除しても、後続の値のID値はリセットされません。たとえば、ID値が20〜25の行をいくつか削除してみましょう。
Delete from employee
where id between 20 and 25
次に、テーブルレコードを表示します。
Select * from employee where id>15
アイデンティティ値の範囲のギャップを示しています。
SQL削除ステートメントとトランザクションログ
SQL deleteは、トランザクションログの各行の削除をログに記録します。 SQLテーブルから数百万のレコードを削除する必要があるとします。 1回のトランザクションで多数のレコードを削除すると、ログファイルが急激に増加し、データベースも使用できなくなる可能性があるため、削除しないでください。途中でトランザクションをキャンセルすると、削除ステートメントをロールバックするのに数時間かかる場合があります。
この場合、常に小さなチャンクの行を削除し、それらのチャンクを定期的にコミットする必要があります。たとえば、一度に10,000行のバッチを削除し、それをコミットして、次のバッチに移動できます。 SQL Serverがチャンクをコミットすると、トランザクションログの増加を制御できます。
ベストプラクティス
- データを削除する前に、必ずバックアップを実行する必要があります。
- デフォルトでは、SQL Serverは暗黙的なトランザクションを使用し、ユーザーに確認せずにレコードをコミットします。ベストプラクティスとして、BeginTransactionを使用して明示的なトランザクションを開始する必要があります。トランザクションをコミットまたはロールバックするための制御を提供します。データベースが完全復旧モードの場合は、トランザクションログのバックアップも頻繁に実行する必要があります。
- トランザクションログの過度の使用を避けるために、データを小さなチャンクで削除する必要があります。また、他のSQLトランザクションのブロックも回避します。
- ユーザーがデータを削除できないように、権限を制限する必要があります。許可されたユーザーのみがSQLテーブルからデータを削除するためのアクセス権を持っている必要があります。
- where句を指定してdeleteステートメントを実行するとします。フィルタリングされたデータをSQLテーブルから削除します。アプリケーションで頻繁にデータを削除する必要がある場合は、ID値を定期的にリセットすることをお勧めします。そうしないと、ID値の枯渇の問題に直面する可能性があります。
- テーブルを空にする場合は、truncateステートメントを使用することをお勧めします。 truncateステートメントは、テーブルからすべてのデータを削除し、最小限のトランザクションログを使用し、ID値の範囲をリセットします。また、テーブルのすべてのページの割り当てをすぐに解除するため、SQLdeleteステートメントよりも高速です。
- テーブルに外部キー制約(親子関係)を使用する場合は、子行から行を削除してから、親テーブルから行を削除する必要があります。親行から行を削除する場合は、[削除時にカスケード]オプションを使用して、子テーブルから行を自動的に削除することもできます。詳細については、「SQLServer外部キーのカスケードを削除してカスケードを更新する」の記事を参照してください。
- topステートメントを使用して行を削除すると、SQLServerは行をランダムに削除します。常に、対応するOrderby句とGroupby句とともにtop句を使用する必要があります。
- deleteステートメントは、参照テーブルの排他的インテントロックを取得します。したがって、その間、他のトランザクションはデータを変更できません。 NOLOCKヒントを使用してデータを読み取ることができます。
- テーブルヒントを使用して、SQLdeleteステートメントのデフォルトのロック動作をオーバーライドすることは避けてください。経験豊富なDBAと開発者のみが使用する必要があります。
重要な考慮事項
SQLのdeleteステートメントを使用してSQLテーブルからデータを削除することには多くの利点がありますが、ご覧のとおり、系統的なアプローチが必要です。常に小さなバッチでデータを削除し、本番インスタンスからデータを削除するときは注意して続行することが重要です。ダウンタイムや将来のパフォーマンスへの影響を回避するには、最小限の時間でデータを回復するためのバックアップ戦略を立てる必要があります。