sql >> Databasteknik >  >> RDS >> Sqlserver

Handledning för SQL Server-tabellpartitionering och partitioner

Problem

I den här artikeln kommer vi att fokusera på demonstrationen av tabellpartitionering. Den enklaste förklaringen av tabellpartitionering kan kallas att dela upp stora tabeller i små. Det här ämnet ger skalbarhet och hanterbarhet.

Vad är tabellpartitionering i SQL Server?

Antag att vi har ett bord och att det växer dag för dag. I det här fallet kan tabellen orsaka vissa problem som måste lösas genom stegen som definieras nedan:

  • Underhåll den här tabellen. Det kommer att ta lång tid och förbruka mer resurser (CPU, IO etc.).
  • Säkerhetskopiera.
  • Låsproblem.

På grund av ovan nämnda skäl behöver vi en bordspartitionering. Detta tillvägagångssätt har följande fördelar:

  • Hanteringsförmåga:Om vi ​​delar upp tabellen kan vi hantera varje partition i tabellen. Till exempel kan vi bara göra en partition av tabellen.
  • Arkiveringsmöjlighet:Vissa partitioner i tabellen används endast av denna anledning. Vi behöver inte säkerhetskopiera denna partition av tabellen. Vi kan använda en filgruppssäkerhetskopia och säkerhetskopiera den endast genom att ändra en partition i tabellen.
  • Frågeprestanda:SQL Server-frågeoptimeraren bestämmer sig för att använda partitionseliminering. Det betyder att SQL Server inte gör någon sökning efter den orelaterade partitionen i tabellen.

Vertikal och horisontell tabellpartitionering i SQL Server

Tabelluppdelning är ett allmänt begrepp. Det finns flera partitioneringstyper som fungerar för särskilda fall. De mest väsentliga och mest använda är de två metoderna:vertikal partitionering och horisontell partitionering.

Varje typs specificitet återspeglar essensen av en tabell som en struktur bestående av kolumner och rader:

• Vertikal partitionering delar upp tabellen i kolumner.
• Horisontell partitionering delar upp tabellen i rader.

Det mest typiska exemplet med vertikal tabelluppdelning är en tabell med anställda med deras uppgifter – namn, e-post, telefonnummer, adresser, födelsedagar, yrken, löner och all annan information som kan behövas. En del av sådan information är konfidentiell. Dessutom behöver operatörer i de flesta fall bara vissa grundläggande data som namn och e-postadresser.

Den vertikala partitioneringen skapar flera "smalare" tabeller med nödvändiga data till hands. Frågor riktar sig endast mot en specifik del. På så sätt minskar företag belastningen, påskyndar uppgifterna och säkerställer att konfidentiell data inte avslöjas.

Den horisontella tabellpartitioneringen resulterar i att en generell tabell delas upp i flera mindre, där varje partikeltabell har samma antal kolumner, men antalet rader är färre. Det är en standardmetod för överdrivna tabeller med kronologiska data.

Till exempel kan en tabell med uppgifter för hela året delas upp i mindre sektioner för varje månad eller vecka. Då kommer frågan bara att gälla en specifik mindre tabell. Horisontell partitionering förbättrar skalbarheten för datavolymerna med deras tillväxt. De partitionerade tabellerna förblir mindre och enkla att bearbeta.

All tabellpartitionering i SQL-server bör övervägas med försiktighet. Ibland måste du begära data från flera partitionerade tabeller samtidigt, och då behöver du JOINs i frågor. Dessutom kan vertikal partitionering fortfarande resultera i stora tabeller, och du måste dela upp dem mer. I ditt arbete bör du lita på besluten för dina specifika affärsändamål.

Nu när vi har klargjort konceptet med tabellpartitionering i SQL Server, är det dags att gå vidare till demonstrationen.

Vi kommer att undvika alla T-SQL-skript och hantera alla tabellpartitionssteg med SQL Server-partitioneringsguiden.

Vad behöver du för att göra SQL-databaspartitioner?

  • WideWorldImporters exempeldatabas
  • SQL Server 2017 Developer Edition

Bilden nedan visar oss hur man designar en bordspartition. Vi kommer att göra en tabellpartition efter år och hitta olika filgrupper.

I det här steget kommer vi att skapa två filgrupper (FG_2013, FG_2014). Högerklicka på en databas och klicka sedan på fliken Filgrupper.

Nu kommer vi att koppla filgrupperna till nya pdf-filer.

Vår databaslagringsstruktur är redo för tabellpartitionering. Vi kommer att hitta tabellen som vi vill ska partitioneras och starta guiden Skapa partition.

På skärmdumpen nedan kommer vi att välja en kolumn som vi vill använda partitionsfunktionen på. Den valda kolumnen är "InvoiceDate".

På de nästa två skärmarna kommer vi att namnge en partitionsfunktion och ett partitionsschema.

En partitionsfunktion kommer att definiera hur man partitionerar för raderna [Sales].[Invoices] baserat på kolumnen InvoiceDate.

Ett partitionsschema kommer att definiera kartor för Sales.Invoices-raderna till filgrupper.

Tilldela partitionerna till filgrupper och ställ in gränserna.

Vänster/Högergräns definierar sidan av varje gränsvärdesintervall som kan vara vänster eller höger. Vi sätter gränser så här och klickar på Uppskatta lagring. Det här alternativet ger oss information om antalet rader som ska placeras i gränserna.

Och slutligen väljer vi Kör omedelbart och klickar sedan på Nästa.

När åtgärden har lyckats klickar du på Stäng.

Som du kan se har vår Sales.Invoices-tabell partitionerats. Den här frågan visar detaljerna för den partitionerade tabellen.

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-partitioneringsprestanda

Vi kommer att jämföra prestanda för partitionerade och icke-partitionerade tabeller för samma tabell. För att göra detta, använd nedanstående fråga och aktivera Inkludera faktisk exekveringsplan.

DECLARE @Dt as date  = '20131231'
SELECT COUNT(InvoiceDate)
  FROM [Sales].[Invoices]
  where InvoiceDate < @Dt

När vi granskar exekveringsplanen kommer vi att veta att den inkluderar egenskaperna "Partionerad", "Faktiskt antal partitioner" och "Faktiskt partitionerad åtkomst".

Den uppdelade egenskapen indikerar att den här tabellen är aktiverad för partition.

Faktiskt antal partitioner egenskap är det totala antalet partitioner som läses av SQL Server-motorn.

Faktiskt partitionerad åtkomst egenskapen är partitionsnummer som bedöms av SQL Server-motorn. SQL Server eliminerar åtkomsten för andra partitioner eftersom det kallas partitionseliminering och får en fördel i fråga om prestanda.

Titta nu på den icke-partitionerade tabellexekveringsplanen.

Huvudskillnaden mellan dessa två exekveringsplaner är Antal rader lästa eftersom den här egenskapen anger hur många rader som läses för den här frågan. Som du kan se från komprimeringsdiagrammet nedan är värdena för partitionerade tabeller för låga. Av denna anledning kommer den att förbruka en låg IO.

Kör sedan frågan och undersök exekveringsplanen.

DECLARE @DtBeg as date  = '20140502'
DECLARE @DtEnd as date  = '20140701'

SELECT COUNT(InvoiceDate)
  FROM [Sales].[Invoices]
  where InvoiceDate between @DtBeg and @DtEnd

Eskalering av lås på partitionsnivå

Låseskalering är en mekanism som används av SQL Server Lock Manager. Det ordnar att låsa en nivå av föremål. När antalet rader som ska låsas ökar, ändrar låshanteraren ett låsobjekt. Detta är hierarkinivån för låseskalering "Rad -> Sida -> Tabell -> Databas". Men i den partitionerade tabellen kan vi låsa en partition eftersom det ökar samtidighet och prestanda. Standardnivån för låseskalering är "TABELL" i SQL Server.

Kör frågan med UPDATE-satsen nedan.

BEGIN TRAN
DECLARE @Dt as date  = '20131221'
UPDATE [Sales].[Invoices] SET CreditNoteReason = 'xxx'   where InvoiceDate < @Dt
SP_LOCK

Den röda rutan definierar ett exklusivt lås som säkerställer att flera uppdateringar inte kan göras av samma resurs samtidigt. Det förekommer i tabellen Fakturor.

Nu kommer vi att ställa in eskaleringsläget för tabellen Sales.Invoices för att automatisera den och köra frågan igen.

ALTER TABLE Sales.Invoices SET (LOCK_ESCALATION = AUTO)

Nu definierar den röda rutan det exklusiva indragslåset som skyddar begärda eller förvärvade exklusiva lås på vissa resurser lägre i hierarkin. Inom kort tillåter denna låsnivå oss att uppdatera eller ta bort andra partitioner av tabeller. Det betyder att vi kan starta en ny uppdatering eller infoga en annan partition i tabellen.

I tidigare inlägg undersökte vi också frågan om att växla mellan tabellpartitionering och gav genomgången. Denna information kan vara till hjälp för dig om du hanterar dessa fall. Se artikeln för mer information.

Referenser

  1. Låslägen
  2. Partitionerade tabeller och index

  1. Hur man laddar upp bilder till MySQL-databasen med PHP-kod

  2. Två kolumner i underfrågan i where-satsen

  3. Databasserverhårdtrender

  4. Hur får man ett datum i formatet ÅÅÅÅ-MM-DD från ett TSQL-datumtidfält?