Probleem
In dit artikel zullen we ons concentreren op de demonstratie van tabelpartitionering. De eenvoudigste verklaring voor het partitioneren van tabellen is het verdelen van grote tabellen in kleine. Dit onderwerp biedt schaalbaarheid en beheerbaarheid.
Wat is tabelpartitionering in SQL Server?
Stel dat we een tafel hebben en deze groeit met de dag. In dit geval kan de tabel enkele problemen veroorzaken die opgelost moeten worden door de onderstaande stappen:
- Behoud deze tabel. Het zal lang duren en meer bronnen verbruiken (CPU, IO enz.).
- Back-up maken.
- Vergrendelingsproblemen.
Om bovengenoemde redenen hebben we een tabelpartitionering nodig. Deze aanpak heeft de volgende voordelen:
- Beheermogelijkheden:als we de tabel opsplitsen, kunnen we elke partitie van de tabel beheren. We kunnen bijvoorbeeld maar één partitie van de tabel maken.
- Archiveringsmogelijkheid:sommige partities van de tabel worden alleen om deze reden gebruikt. We hoeven geen back-up te maken van deze partitie van de tabel. We kunnen alleen een back-up van een bestandsgroep gebruiken en er een back-up van maken door een partitie van de tabel te wijzigen.
- Queryprestaties:SQL Server-queryoptimalisatie besluit partitie-eliminatie te gebruiken. Het betekent dat SQL Server niet zoekt naar de niet-gerelateerde partitie van de tabel.
Verticale en horizontale tabelpartitionering in SQL Server
Tabelverdeling is een algemeen concept. Er zijn verschillende typen partitionering die voor bepaalde gevallen werken. De meest essentiële en meest gebruikte zijn de twee benaderingen:verticale partitionering en horizontale partitionering.
De specificiteit van elk type weerspiegelt de essentie van een tabel als een structuur bestaande uit kolommen en rijen:
• Verticale partities splitst de tabel in kolommen.
• Horizontale partities splitst de tabel in rijen.
Het meest typische voorbeeld van een verticale tabelindeling is een tabel met werknemers met hun gegevens:namen, e-mails, telefoonnummers, adressen, verjaardagen, beroepen, salarissen en alle andere informatie die nodig kan zijn. Een deel van dergelijke gegevens is vertrouwelijk. Bovendien hebben operators in de meeste gevallen slechts enkele basisgegevens nodig, zoals namen en e-mailadressen.
Door de verticale partitionering ontstaan meerdere “smallere” tabellen met de benodigde gegevens bij de hand. Query's zijn alleen gericht op een specifiek onderdeel. Op deze manier verminderen bedrijven de belasting, versnellen ze de taken en zorgen ze ervoor dat vertrouwelijke gegevens niet worden onthuld.
De horizontale tabelpartitionering resulteert in het splitsen van één algemene tabel in meerdere kleinere, waarbij elke deeltjestabel hetzelfde aantal kolommen heeft, maar het aantal rijen is minder. Het is een standaardaanpak voor buitensporige tabellen met chronologische gegevens.
Een tabel met de gegevens voor het hele jaar kan bijvoorbeeld worden opgedeeld in kleinere secties voor elke maand of week. De query heeft dan slechts betrekking op één specifieke kleinere tabel. Horizontale partitionering verbetert de schaalbaarheid voor de datavolumes met hun groei. De gepartitioneerde tabellen blijven kleiner en gemakkelijk te verwerken.
Elke tabelpartitionering in SQL-server moet zorgvuldig worden overwogen. Soms moet je de gegevens van meerdere gepartitioneerde tabellen tegelijk opvragen, en dan heb je JOIN's nodig in query's. Trouwens, verticale partitionering kan nog steeds resulteren in grote tabellen, en je zult ze meer moeten splitsen. In uw werk moet u vertrouwen op de beslissingen voor uw specifieke zakelijke doeleinden.
Nu we het concept van de tabelpartitionering in SQL Server hebben verduidelijkt, is het tijd om door te gaan met de demonstratie.
We gaan elk T-SQL-script vermijden en alle stappen van de tabelpartitie afhandelen met de SQL Server Partitioning-wizard.
Wat heb je nodig om SQL-databasepartities te maken?
- WideWorldImporters-voorbeelddatabase
- SQL Server 2017 Developer Edition
De onderstaande afbeelding laat ons zien hoe u een tabelpartitie ontwerpt. We zullen een tabelpartitie maken op jaarbasis en verschillende bestandsgroepen lokaliseren.
Bij deze stap zullen we twee bestandsgroepen maken (FG_2013, FG_2014). Klik met de rechtermuisknop op een database en klik vervolgens op het tabblad Bestandsgroepen.
Nu zullen we de bestandsgroepen verbinden met nieuwe pdf-bestanden.
Onze database-opslagstructuur is klaar voor tabelpartitionering. We zoeken de tabel die we willen partitioneren en starten de wizard Partitie maken.
Op de onderstaande schermafbeelding selecteren we een kolom waarop we de partitiefunctie willen toepassen. De geselecteerde kolom is "Factuurdatum".
Op de volgende twee schermen zullen we een partitiefunctie en een partitieschema een naam geven.
Een partitiefunctie zal bepalen hoe partities moeten worden uitgevoerd voor de [Sales].[Facturen]-rijen op basis van de InvoiceDate-kolom.
Een partitieschema definieert mappen voor de Sales.Invoices-rijen naar bestandsgroepen.
Wijs de partities toe aan bestandsgroepen en stel de grenzen in.
Left/Right Boundary definieert de zijde van elk grenswaarde-interval dat links of rechts kan zijn. We zullen op deze manier grenzen stellen en klikken op Opslag schatten. Deze optie geeft ons de informatie over het aantal rijen dat in de grenzen moet worden geplaatst.
En tot slot zullen we Onmiddellijk Uitvoeren selecteren en vervolgens op Volgende klikken.
Zodra de bewerking is geslaagd, klikt u op Sluiten.
Zoals u kunt zien, is onze tabel Sales.Invoices gepartitioneerd. Deze query toont de details van de gepartitioneerde tabel.
SELECT
OBJECT_SCHEMA_NAME(pstats.object_id) AS SchemaName
,OBJECT_NAME(pstats.object_id) AS TableName
,ps.name AS PartitionSchemeName
,ds.name AS PartitionFilegroupName
,pf.name AS PartitionFunctionName
,CASE pf.boundary_value_on_right WHEN 0 THEN 'Range Left' ELSE 'Range Right' END AS PartitionFunctionRange
,CASE pf.boundary_value_on_right WHEN 0 THEN 'Upper Boundary' ELSE 'Lower Boundary' END AS PartitionBoundary
,prv.value AS PartitionBoundaryValue
,c.name AS PartitionKey
,CASE
WHEN pf.boundary_value_on_right = 0
THEN c.name + ' > ' + CAST(ISNULL(LAG(prv.value) OVER(PARTITION BY pstats.object_id ORDER BY pstats.object_id, pstats.partition_number), 'Infinity') AS VARCHAR(100)) + ' and ' + c.name + ' <= ' + CAST(ISNULL(prv.value, 'Infinity') AS VARCHAR(100))
ELSE c.name + ' >= ' + CAST(ISNULL(prv.value, 'Infinity') AS VARCHAR(100)) + ' and ' + c.name + ' < ' + CAST(ISNULL(LEAD(prv.value) OVER(PARTITION BY pstats.object_id ORDER BY pstats.object_id, pstats.partition_number), 'Infinity') AS VARCHAR(100))
END AS PartitionRange
,pstats.partition_number AS PartitionNumber
,pstats.row_count AS PartitionRowCount
,p.data_compression_desc AS DataCompression
FROM sys.dm_db_partition_stats AS pstats
INNER JOIN sys.partitions AS p ON pstats.partition_id = p.partition_id
INNER JOIN sys.destination_data_spaces AS dds ON pstats.partition_number = dds.destination_id
INNER JOIN sys.data_spaces AS ds ON dds.data_space_id = ds.data_space_id
INNER JOIN sys.partition_schemes AS ps ON dds.partition_scheme_id = ps.data_space_id
INNER JOIN sys.partition_functions AS pf ON ps.function_id = pf.function_id
INNER JOIN sys.indexes AS i ON pstats.object_id = i.object_id AND pstats.index_id = i.index_id AND dds.partition_scheme_id = i.data_space_id AND i.type <= 1 /* Heap or Clustered Index */
INNER JOIN sys.index_columns AS ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id AND ic.partition_ordinal > 0
INNER JOIN sys.columns AS c ON pstats.object_id = c.object_id AND ic.column_id = c.column_id
LEFT JOIN sys.partition_range_values AS prv ON pf.function_id = prv.function_id AND pstats.partition_number = (CASE pf.boundary_value_on_right WHEN 0 THEN prv.boundary_id ELSE (prv.boundary_id+1) END)
WHERE pstats.object_id = OBJECT_ID('Sales.Invoices')
ORDER BY TableName, PartitionNumber;
MS SQL Server-partitioneringsprestaties
We zullen de gepartitioneerde en niet-gepartitioneerde tabelprestaties voor dezelfde tabel vergelijken. Gebruik hiervoor de onderstaande query en activeer Inclusief daadwerkelijk uitvoeringsplan.
DECLARE @Dt as date = '20131231'
SELECT COUNT(InvoiceDate)
FROM [Sales].[Invoices]
where InvoiceDate < @Dt
Wanneer we het uitvoeringsplan onderzoeken, komen we te weten dat het de eigenschappen 'Gepartitioneerd', 'Eigenlijk aantal partities' en 'Eigenlijk gepartitioneerd toegankelijk' bevat.
De Gepartitioneerde eigenschap geeft aan dat deze tabel is ingeschakeld voor partitie.
Het werkelijke aantal partities eigenschap is het totale aantal partities dat wordt gelezen door de SQL Server-engine.
De werkelijk gepartitioneerde toegang eigenschap is partitienummers beoordeeld door SQL Server-engine. SQL Server elimineert de toegang voor andere partities omdat dit een partitie-eliminatie wordt genoemd en krijgt een voordeel op de queryprestaties.
Kijk nu eens naar het uitvoeringsplan voor niet-gepartitioneerde tabellen.
Het belangrijkste verschil tussen deze twee uitvoeringsplannen is Aantal gelezen rijen omdat deze eigenschap aangeeft hoeveel rijen er voor deze query worden gelezen. Zoals u kunt zien in de onderstaande compressiegrafiek, zijn de gepartitioneerde tabelwaarden te laag. Om deze reden zal het een lage IO verbruiken.
Voer vervolgens de query uit en onderzoek het uitvoeringsplan.
DECLARE @DtBeg as date = '20140502'
DECLARE @DtEnd as date = '20140701'
SELECT COUNT(InvoiceDate)
FROM [Sales].[Invoices]
where InvoiceDate between @DtBeg and @DtEnd
Slotescalatie op partitieniveau
Lock-escalatie is een mechanisme dat wordt gebruikt door SQL Server Lock Manager. Het regelt om een niveau van objecten te vergrendelen. Wanneer het aantal te vergrendelen rijen toeneemt, verandert de vergrendelingsmanager een vergrendelingsobject. Dit is het hiërarchieniveau van vergrendelingsescalatie "Rij -> Pagina -> Tabel -> Database". Maar in de gepartitioneerde tabel kunnen we één partitie vergrendelen omdat dit de gelijktijdigheid en prestaties verhoogt. Het standaard niveau van lock-escalatie is "TABEL" in SQL Server.
Voer de query uit met behulp van de onderstaande UPDATE-instructie.
BEGIN TRAN
DECLARE @Dt as date = '20131221'
UPDATE [Sales].[Invoices] SET CreditNoteReason = 'xxx' where InvoiceDate < @Dt
SP_LOCK
Het rode vak definieert een exclusieve vergrendeling die ervoor zorgt dat niet meerdere updates tegelijkertijd voor dezelfde bron kunnen worden gemaakt. Het komt voor in de tabel Facturen.
Nu gaan we de escalatiemodus voor de tabel Sales.Invoices instellen om deze te automatiseren en de query opnieuw uit te voeren.
ALTER TABLE Sales.Invoices SET (LOCK_ESCALATION = AUTO)
Nu definieert het rode vak het inspringende exclusieve slot dat gevraagde of verworven exclusieve sloten op sommige bronnen lager in de hiërarchie beschermt. Kortom, dit vergrendelingsniveau stelt ons in staat om andere partities van tabellen bij te werken of te verwijderen. Dat betekent dat we een nieuwe update kunnen starten of een andere partitie van de tabel kunnen invoegen.
In eerdere berichten hebben we ook het probleem van het schakelen tussen tabelpartitionering onderzocht en de walkthrough gegeven. Deze informatie kan u van pas komen als u met deze zaken te maken krijgt. Raadpleeg het artikel voor meer informatie.
Referenties
- Vergrendelingsmodi
- Gepartitioneerde tabellen en indexen