In relationele databases maken we tabellen om gegevens in verschillende formaten op te slaan. SQL Server slaat gegevens op in een rij- en kolomindeling die een waarde bevat die aan elk gegevenstype is gekoppeld. Wanneer we SQL-tabellen ontwerpen, definiëren we gegevenstypen zoals integer, float, decimaal, varchar en bit. Een tabel waarin klantgegevens zijn opgeslagen, kan bijvoorbeeld velden bevatten zoals klantnaam, e-mailadres, adres, staat, land enzovoort. Verschillende SQL-commando's worden uitgevoerd op een SQL-tabel en kunnen worden onderverdeeld in de volgende categorieën:
- Data Definition Language (DDL): Deze opdrachten worden gebruikt om de database-objecten in een database te maken en te wijzigen.
- Maken: Maakt objecten
- Wijzigen: Wijzigt objecten
- Laat vallen: Verwijdert objecten
- Truncate: Verwijdert alle gegevens uit een tabel
- Taal voor gegevensmanipulatie (DML): Met deze opdrachten worden gegevens in de database ingevoegd, opgehaald, gewijzigd, verwijderd en bijgewerkt.
- Selecteer: Haalt gegevens op uit een enkele of meerdere tabellen
- Invoegen: Voegt nieuwe gegevens toe aan een tabel
- Bijwerken: Wijzigt bestaande gegevens
- Verwijderen: Verwijdert bestaande records in een tabel
- Taal voor gegevensbeheer (DCL): Deze commando's zijn gekoppeld aan rechten of machtigingen in een database.
- Toekenning: Wijst machtigingen toe aan een gebruiker
- Intrekken: Trekt machtigingen van een gebruiker in
- Taal voor transactiebeheer (TCL): Deze commando's besturen transacties in een database.
- Bevestigen: Slaat de wijzigingen op die door de zoekopdracht zijn aangebracht
- Terugdraaien: Draait een expliciete of impliciete transactie terug naar het begin van de transactie, of naar een opslagpunt binnen de transactie
- Transacties opslaan: Stelt een opslagpunt of markering in binnen een transactie
Stel dat u klantordergegevens hebt opgeslagen in een SQL-tabel. Als u continu gegevens in deze tabel zou blijven invoegen, zou de tabel miljoenen records kunnen bevatten, wat prestatieproblemen binnen uw applicaties zou veroorzaken. Uw indexonderhoud kan ook zeer tijdrovend worden. Vaak hoeft u orders die ouder zijn dan drie jaar niet te bewaren. In deze gevallen kunt u die records uit de tabel verwijderen. Dit zou opslagruimte besparen en uw onderhoudsinspanningen verminderen.
U kunt op twee manieren gegevens uit een SQL-tabel verwijderen:
- Een SQL delete-instructie gebruiken
- Een truncate gebruiken
We zullen later kijken naar het verschil tussen deze SQL-opdrachten. Laten we eerst de SQL delete-instructie bekijken.
Een SQL delete-instructie zonder enige voorwaarden
In DML-instructies (Data Manipulation Language) verwijdert een SQL-deletie-instructie de rijen uit een tabel. U kunt een specifieke rij of alle rijen verwijderen. Een eenvoudige delete-instructie vereist geen argumenten.
Laten we een Orders SQL-tabel maken met behulp van het onderstaande script. Deze tabel heeft drie kolommen [OrderID], [ProductName] en [ProductQuantity].
Create Table Orders
( OrderID int,
ProductName varchar(50),
ProductQuantity int
)
Voeg een paar records toe aan deze tabel.
Insert into Orders values (1,'ABC books',10),
(2,'XYZ',100),
(3,'SQL book',50)
Stel nu dat we de tabelgegevens willen verwijderen. U kunt de tabelnaam specificeren om gegevens te verwijderen met behulp van de delete-instructie. Beide SQL-instructies zijn hetzelfde. We kunnen de tabelnaam specificeren met het (optionele) trefwoord of de tabelnaam direct na het verwijderen specificeren.
Delete Orders
Go
Delete from Orders
GO
Een SQL-verwijderinstructie met gefilterde gegevens
Deze SQL-verwijderinstructies verwijderen alle gegevens van de tabel. Meestal verwijderen we niet alle rijen uit een SQL-tabel. Om een specifieke rij te verwijderen, kunnen we een where-clausule toevoegen met de delete-opdracht. De where-clausule bevat de filtercriteria en bepaalt uiteindelijk welke rij(en) moeten worden verwijderd.
Stel dat we bijvoorbeeld order id 1 willen verwijderen. Zodra we een where-clausule hebben toegevoegd, controleert SQL Server eerst de corresponderende rijen en verwijdert die specifieke rijen.Delete Orders where orderid=1
Als de where-clausule-voorwaarde onwaar is, worden er geen rijen verwijderd. Zo hebben we de bestelde 1 uit de besteltabel verwijderd. Als we de instructie opnieuw uitvoeren, vindt deze geen rijen die aan de voorwaarde van de where-clausule voldoen. In dit geval retourneert het 0 betrokken rijen.
SQL delete-instructie en TOP-clausule
U kunt het TOP-statement gebruiken om de rijen ook te verwijderen. De onderstaande zoekopdracht verwijdert bijvoorbeeld de top 100 rijen uit de tabel Orders.
Delete top (100) [OrderID]
from Orders
Omdat we geen 'ORDER BY' hebben gespecificeerd, kiest het willekeurige rijen en verwijdert deze. We kunnen de Order by-clausule gebruiken om de gegevens te sorteren en de bovenste rijen te verwijderen. In de onderstaande query sorteert het de [OrderID] in aflopende volgorde en verwijdert het vervolgens uit de [Orders]-tabel.
Delete from Orders where [OrderID] In
(
Select top 100 [OrderID] FROM Orders
order by [OrderID] Desc
)
Rijen verwijderen op basis van een andere tabel
Soms moeten we rijen verwijderen op basis van een andere tabel. Deze tabel kan in dezelfde database voorkomen of niet.
- Tabel opzoeken
We kunnen de tabelopzoekmethode of SQL-join gebruiken om deze rijen te verwijderen. We willen bijvoorbeeld rijen uit de tabel [Orders] verwijderen die aan de volgende voorwaarde voldoen:
Het zou corresponderende rijen moeten hebben in de [dbo].[Klant] tabel.
Kijk naar de onderstaande query, hier hebben we een select-statement in de where-clausule van het delete-statement. SQL Server haalt eerst de rijen op die voldoen aan de select-instructie en verwijdert die rijen vervolgens uit de [Orders]-tabel met behulp van de SQL delete-instructie.
Delete Orders where orderid in
(Select orderid
from Customer)
- SQL deelnemen
Als alternatief kunnen we SQL-joins tussen deze tabellen gebruiken en de rijen verwijderen. In de onderstaande query voegen we de tabellen [Orders]] samen met de tabel [Klant]. Een SQL-join werkt altijd op een gemeenschappelijke kolom tussen de tabellen. We hebben een kolom [OrderID] die beide tabellen samenvoegt.
DELETE Orders
FROM Orders o
INNER JOIN Customer c ON o.orderid=c.orderid
Laten we, om de bovenstaande verwijderingsverklaring te begrijpen, het daadwerkelijke uitvoeringsplan bekijken.
Volgens het uitvoeringsplan voert het een tafelscan uit op beide tabellen, haalt het de overeenkomende gegevens op en verwijdert ze uit de tabel Orders.
- Gemeenschappelijke tabeluitdrukking (CTE)
We kunnen een Common Table Expression (CTE) gebruiken om de rijen ook uit een SQL-tabel te verwijderen. Eerst definiëren we een CTE om de rij te vinden die we willen verwijderen.
Vervolgens voegen we ons bij de CTE met de SQL-tabel Orders en verwijderen we de rijen.
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;
Impact op het identiteitsbereik
Identiteitskolommen in SQL Server genereren unieke, opeenvolgende waarden voor uw kolom. Ze worden voornamelijk gebruikt om een rij in de SQL-tabel op unieke wijze te identificeren. Een primaire sleutelkolom is ook een goede keuze voor een geclusterde index in SQL Server.
In het onderstaande script hebben we een [Employee]-tabel. Deze tabel heeft een identiteitskolom-ID.
Create Table Employee
(
id int identity(1,1),
[Name] varchar(50)
)
We hebben 50 records in deze tabel ingevoegd die de identiteitswaarden voor de id-kolom hebben gegenereerd.
Declare @id int=1
While(@id<=50)
BEGIN
Insert into Employee([Name]) values('Test'+CONVERT(VARCHAR,@ID))
Set @id=@id+1
END
Als we een paar rijen uit de SQL-tabel verwijderen, worden de identiteitswaarden voor de volgende waarden niet opnieuw ingesteld. Laten we bijvoorbeeld een paar rijen verwijderen met identiteitswaarden 20 tot 25.
Delete from employee
where id between 20 and 25
Bekijk nu de tabelrecords.
Select * from employee where id>15
Het toont de kloof in het identiteitswaardebereik.
SQL delete-instructie en het transactielogboek
SQL delete registreert elke rijverwijdering in het transactielogboek. Stel dat u miljoenen records uit een SQL-tabel moet verwijderen. U wilt niet een groot aantal records in een enkele transactie verwijderen, omdat uw logbestand hierdoor exponentieel kan groeien en uw database mogelijk ook niet beschikbaar is. Als u een transactie halverwege annuleert, kan het uren duren om een verwijderopdracht terug te draaien.
In dit geval moet je rijen altijd in kleine stukjes verwijderen en die stukjes regelmatig vastleggen. U kunt bijvoorbeeld een batch van 10.000 rijen tegelijk verwijderen, deze vastleggen en naar de volgende batch gaan. Wanneer SQL Server de chunk commit, kan de groei van het transactielogboek worden gecontroleerd.
Praktische tips
- U moet altijd een back-up maken voordat u gegevens verwijdert.
- Standaard gebruikt SQL Server impliciete transacties en worden de records vastgelegd zonder dat de gebruiker erom vraagt. Als best practice moet u een expliciete transactie starten met Begin transactie. Het geeft u de controle om de transactie vast te leggen of terug te draaien. U moet ook regelmatig back-ups van transactielogboeken maken als uw database zich in de volledige herstelmodus bevindt.
- U wilt gegevens in kleine stukjes verwijderen om overmatig gebruik van transactielogboeken te voorkomen. Het vermijdt ook blokkades voor andere SQL-transacties.
- U moet de machtigingen beperken zodat gebruikers geen gegevens kunnen verwijderen. Alleen de geautoriseerde gebruikers zouden toegang moeten hebben om gegevens uit een SQL-tabel te verwijderen.
- U wilt de delete-opdracht uitvoeren met een where-clausule. Het verwijdert gefilterde gegevens uit een SQL-tabel. Als uw toepassing regelmatig gegevens moet verwijderen, is het een goed idee om de identiteitswaarden regelmatig opnieuw in te stellen. Anders kunt u problemen krijgen met uitputting van identiteitswaarden.
- In het geval dat je de tabel leeg wilt maken, is het aan te raden om het truncate statement te gebruiken. De truncate-instructie verwijdert alle gegevens uit een tabel, gebruikt minimale transactieregistratie, stelt het identiteitswaardebereik opnieuw in en is sneller dan de SQL-deletie-instructie omdat alle pagina's voor de tabel onmiddellijk ongedaan worden gemaakt.
- Als u beperkingen voor externe sleutels (ouder-kindrelatie) gebruikt voor uw tabellen, moet u de rij verwijderen uit een onderliggende rij en vervolgens uit de bovenliggende tabel. Als u de rij uit de bovenliggende rij verwijdert, kunt u ook de optie trapsgewijs verwijderen gebruiken om de rij automatisch uit een onderliggende tabel te verwijderen. Raadpleeg het artikel:Cascade verwijderen en cascade updaten in externe SQL Server-sleutel voor meer inzichten.
- Als u de instructie top gebruikt om de rijen te verwijderen, verwijdert SQL Server de rijen willekeurig. U moet altijd de bovenste clausule gebruiken met de bijbehorende Order by en Group by clausule.
- Een delete-instructie krijgt een exclusieve intentievergrendeling op de referentietabel; daarom kunnen gedurende die tijd geen andere transacties de gegevens wijzigen. U kunt de NOLOCK-hint gebruiken om de gegevens te lezen.
- U moet het gebruik van de tabelhint vermijden om het standaard vergrendelingsgedrag van de SQL delete-instructie te negeren; het mag alleen worden gebruikt door ervaren DBA's en ontwikkelaars.
Belangrijke overwegingen
Er zijn veel voordelen aan het gebruik van SQL-verwijderinstructies om gegevens uit een SQL-tabel te verwijderen, maar zoals u kunt zien, vereist dit een methodische aanpak. Het is belangrijk om gegevens altijd in kleine batches te verwijderen en voorzichtig te werk te gaan bij het verwijderen van gegevens uit een productie-instantie. Het hebben van een back-upstrategie om gegevens in de minimale tijd te herstellen, is een must om downtime of toekomstige prestatie-impact te voorkomen.