Database
 sql >> Baza danych >  >> RDS >> Database

Kompresja i jej wpływ na wydajność

Jedną z wielu nowych funkcji wprowadzonych w SQL Server 2008 była kompresja danych. Kompresja na poziomie wiersza lub strony zapewnia możliwość zaoszczędzenia miejsca na dysku, z kompromisem polegającym na tym, że do kompresji i dekompresji danych potrzebuje nieco więcej procesora. Często twierdzi się, że większość systemów jest związana z IO, a nie z procesorem, więc kompromis jest tego wart. Połów? Aby korzystać z kompresji danych, trzeba było korzystać z wersji Enterprise. Wraz z wydaniem dodatku SP1 dla SQL Server 2016 to się zmieniło! Jeśli używasz wersji Standard programu SQL Server 2016 SP1 lub nowszej, możesz teraz korzystać z kompresji danych. Dostępna jest również nowa wbudowana funkcja kompresji, KOMPRESJA (i jej odpowiednik DEKOMPRESJA). Kompresja danych nie działa na danych poza wierszem, więc jeśli masz w tabeli kolumnę taką jak NVARCHAR(MAX) z wartościami zwykle większymi niż 8000 bajtów, dane nie zostaną skompresowane (dziękuję Adamowi Machaniowi za to przypomnienie) . Funkcja COMPRESS rozwiązuje ten problem i kompresuje dane do rozmiaru 2 GB. Co więcej, chociaż twierdzę, że funkcja powinna być używana tylko w przypadku dużych danych poza wierszami, pomyślałem, że porównanie jej bezpośrednio z kompresją wierszy i stron jest opłacalnym eksperymentem.

USTAWIENIA

W przypadku danych testowych pracuję ze skryptu, którego Aaron Bertrand używał wcześniej, ale wprowadziłem kilka poprawek. Stworzyłem osobną bazę danych do testowania, ale możesz użyć tempdb lub innej przykładowej bazy danych, a następnie zacząłem od tabeli Klienci, która ma trzy kolumny NVARCHAR. Rozważałem utworzenie większych kolumn i wypełnienie ich ciągami powtarzających się liter, ale użycie czytelnego tekstu daje próbkę, która jest bardziej realistyczna, a tym samym zapewnia większą dokładność.

Uwaga: Jeśli jesteś zainteresowany wdrożeniem kompresji i chcesz wiedzieć, jak wpłynie ona na pamięć masową i wydajność w Twoim środowisku, BARDZO POLECAM TESTOWANIE JĄ. Podaję Ci metodologię z przykładowymi danymi; wdrożenie tego w swoim środowisku nie powinno wiązać się z dodatkową pracą.

Jak zauważysz poniżej, po utworzeniu bazy danych włączamy Query Store. Po co tworzyć osobną tabelę, aby spróbować śledzić nasze metryki wydajności, skoro możemy po prostu korzystać z funkcji wbudowanych w SQL Server?!

USE [master];
GO
 
CREATE DATABASE [CustomerDB]
 CONTAINMENT = NONE
 ON  PRIMARY 
 (
   NAME = N'CustomerDB', FILENAME = N'C:\Databases\CustomerDB.mdf' , 
   SIZE = 4096MB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB 
 )
 LOG ON 
 ( 
   NAME = N'CustomerDB_log', FILENAME = N'C:\Databases\CustomerDB_log.ldf' , 
   SIZE = 2048MB , MAXSIZE = UNLIMITED , FILEGROWTH = 65536KB 
 );
GO
 
ALTER DATABASE [CustomerDB] SET COMPATIBILITY_LEVEL = 130;
GO
ALTER DATABASE [CustomerDB] SET RECOVERY SIMPLE;
GO
ALTER DATABASE [CustomerDB] SET QUERY_STORE = ON;
GO
ALTER DATABASE [CustomerDB] SET QUERY_STORE 
(
  OPERATION_MODE = READ_WRITE, 
  CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30), 
  DATA_FLUSH_INTERVAL_SECONDS = 60,  
  INTERVAL_LENGTH_MINUTES = 5, 
  MAX_STORAGE_SIZE_MB = 256, 
  QUERY_CAPTURE_MODE = ALL, 
  SIZE_BASED_CLEANUP_MODE = AUTO, 
  MAX_PLANS_PER_QUERY = 200
);
GO

Teraz skonfigurujemy kilka rzeczy w bazie danych:

USE [CustomerDB];
GO
ALTER DATABASE SCOPED CONFIGURATION SET MAXDOP = 0;
GO
 
-- note: I removed the unique index on [Email] that was in Aaron's version
CREATE TABLE [dbo].[Customers]
(
	[CustomerID] [int] NOT NULL,
	[FirstName] [nvarchar](64) NOT NULL,
	[LastName] [nvarchar](64) NOT NULL,
	[EMail] [nvarchar](320) NOT NULL,
	[Active] [bit] NOT NULL DEFAULT 1,
	[Created] [datetime] NOT NULL DEFAULT SYSDATETIME(),
	[Updated] [datetime] NULL,
  CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED ([CustomerID])
);
GO
 
CREATE NONCLUSTERED INDEX [Active_Customers] 
ON [dbo].[Customers]([FirstName],[LastName],[EMail])
WHERE ([Active]=1);
GO
 
CREATE NONCLUSTERED INDEX [PhoneBook_Customers] 
ON [dbo].[Customers]([LastName],[FirstName])
INCLUDE ([EMail]);

Po utworzeniu tabeli dodamy trochę danych, ale dodajemy 5 milionów wierszy zamiast 1 miliona. Uruchomienie na moim laptopie zajmuje około ośmiu minut.

INSERT dbo.Customers WITH (TABLOCKX) 
  (CustomerID, FirstName, LastName, EMail, [Active])
  SELECT rn = ROW_NUMBER() OVER (ORDER BY n), fn, ln, em, a
  FROM 
  (
    SELECT TOP (5000000) fn, ln, em, a = MAX(a), n = MAX(NEWID())
    FROM
    (
      SELECT fn, ln, em, a, r = ROW_NUMBER() OVER (PARTITION BY em ORDER BY em)
      FROM
      (
        SELECT TOP (20000000)
          fn = LEFT(o.name,  64), 
          ln = LEFT(c.name,  64), 
          em = LEFT(o.name,  LEN(c.name)%5+1) + '.' 
             + LEFT(c.name,  LEN(o.name)%5+2) + '@' 
             + RIGHT(c.name, LEN(o.name + c.name)%12 + 1) 
             + LEFT(RTRIM(CHECKSUM(NEWID())),3) + '.com', 
          a  = CASE WHEN c.name LIKE '%y%' THEN 0 ELSE 1 END
        FROM sys.all_objects AS o CROSS JOIN sys.all_columns AS c 
        ORDER BY NEWID()
      ) AS x
    ) AS y WHERE r = 1 
    GROUP BY fn, ln, em 
    ORDER BY n
  ) AS z 
  ORDER BY rn;
GO

Teraz utworzymy jeszcze trzy tabele:jedną do kompresji wierszy, jedną do kompresji stron i jedną do funkcji KOMPRESUJ. Zauważ, że w przypadku funkcji KOMPRESUJ, musisz utworzyć kolumny jako typy danych VARBINARY. W rezultacie w tabeli nie ma indeksów nieklastrowych (ponieważ nie można utworzyć klucza indeksu w kolumnie varbinary).

CREATE TABLE [dbo].[Customers_Page]
(
	[CustomerID] [int] NOT NULL,
	[FirstName] [nvarchar](64) NOT NULL,
	[LastName] [nvarchar](64) NOT NULL,
	[EMail] [nvarchar](320) NOT NULL,
	[Active] [bit] NOT NULL DEFAULT 1,
	[Created] [datetime] NOT NULL DEFAULT SYSDATETIME(),
	[Updated] [datetime] NULL,
  CONSTRAINT [PK_Customers_Page] PRIMARY KEY CLUSTERED ([CustomerID])
);
GO
 
CREATE NONCLUSTERED INDEX [Active_Customers_Page] 
ON [dbo].[Customers_Page]([FirstName],[LastName],[EMail])
WHERE ([Active]=1);
GO
 
CREATE NONCLUSTERED INDEX [PhoneBook_Customers_Page] 
ON [dbo].[Customers_Page]([LastName],[FirstName])
INCLUDE ([EMail]);
GO
 
CREATE TABLE [dbo].[Customers_Row]
(
	[CustomerID] [int] NOT NULL,
	[FirstName] [nvarchar](64) NOT NULL,
	[LastName] [nvarchar](64) NOT NULL,
	[EMail] [nvarchar](320) NOT NULL,
	[Active] [bit] NOT NULL DEFAULT 1,
	[Created] [datetime] NOT NULL DEFAULT SYSDATETIME(),
	[Updated] [datetime] NULL,
  CONSTRAINT [PK_Customers_Row] PRIMARY KEY CLUSTERED ([CustomerID])
);
GO
 
CREATE NONCLUSTERED INDEX [Active_Customers_Row] 
ON [dbo].[Customers_Row]([FirstName],[LastName],[EMail])
WHERE ([Active]=1);
GO
 
CREATE NONCLUSTERED INDEX [PhoneBook_Customers_Row] 
ON [dbo].[Customers_Row]([LastName],[FirstName])
INCLUDE ([EMail]);
GO
 
CREATE TABLE [dbo].[Customers_Compress]
(
	[CustomerID] [int] NOT NULL,
	[FirstName] [varbinary](max) NOT NULL,
	[LastName] [varbinary](max) NOT NULL,
	[EMail] [varbinary](max) NOT NULL,
	[Active] [bit] NOT NULL DEFAULT 1,
	[Created] [datetime] NOT NULL DEFAULT SYSDATETIME(),
	[Updated] [datetime] NULL,
  CONSTRAINT [PK_Customers_Compress] PRIMARY KEY CLUSTERED ([CustomerID])
);
GO

Następnie skopiujemy dane z [dbo].[Klienci] do pozostałych trzech tabel. To jest zwykłe WSTAWIANIE dla naszych tabel stron i wierszy i zajmuje około dwóch do trzech minut dla każdego WSTAWIANIA, ale istnieje problem ze skalowalnością funkcji KOMPRESUJ:próba wstawienia 5 milionów wierszy za jednym zamachem po prostu nie jest rozsądna. Poniższy skrypt wstawia wiersze w partiach po 50 000 i wstawia tylko 1 milion wierszy zamiast 5 milionów. Wiem, to znaczy, że nie jesteśmy tutaj prawdziwymi jabłkami do porównania, ale nie mam z tym problemu. Wstawienie 1 miliona wierszy na moim komputerze zajmuje 10 minut; możesz dostosować skrypt i wstawić 5 milionów wierszy do własnych testów.

INSERT dbo.Customers_Page WITH (TABLOCKX)
  (CustomerID, FirstName, LastName, EMail, [Active])
SELECT CustomerID, FirstName, LastName, EMail, [Active]
FROM dbo.Customers;
GO
 
INSERT dbo.Customers_Row WITH (TABLOCKX)
  (CustomerID, FirstName, LastName, EMail, [Active])
SELECT CustomerID, FirstName, LastName, EMail, [Active]
FROM dbo.Customers;
GO
 
SET NOCOUNT ON
 
DECLARE @StartID INT = 1
DECLARE @EndID INT = 50000
DECLARE @Increment INT = 50000
DECLARE @IDMax INT = 1000000
 
WHILE @StartID < @IDMax
BEGIN
 
	INSERT dbo.Customers_Compress WITH (TABLOCKX) (CustomerID, FirstName, LastName, EMail, [Active])
	SELECT top 100000 CustomerID, COMPRESS(FirstName), COMPRESS(LastName), COMPRESS(EMail), [Active]
	FROM dbo.Customers
	WHERE [CustomerID] BETWEEN @StartID AND @EndID;
 
	SET @StartID = @StartID + @Increment;
	SET @EndID = @EndID + @Increment;
END

Po wypełnieniu wszystkich naszych tabel możemy sprawdzić rozmiar. W tym momencie nie zaimplementowaliśmy kompresji ROW ani PAGE, ale użyto funkcji KOMPRESUJ:

SELECT [o].[name], [i].[index_id], [i].[name], [p].[rows],  
(8*SUM([au].[used_pages]))/1024 AS [IndexSize(MB)], [p].[data_compression_desc]
FROM [sys].[allocation_units] [au]
JOIN [sys].[partitions] [p]
	ON [au].[container_id] = [p].[partition_id]
JOIN [sys].[objects] [o] 
	ON [p].[object_id] = [o].[object_id]
JOIN [sys].[indexes] [i]
	ON [p].[object_id] = [i].[object_id] AND [p].[index_id] = [i].[index_id]
WHERE [o].[is_ms_shipped] = 0
GROUP BY [o].[name], [i].[index_id], [i].[name], [p].[rows], [p].[data_compression_desc]
ORDER BY [o].[name], [i].[index_id];

Rozmiar tabeli i indeksu po wstawieniu

Zgodnie z oczekiwaniami wszystkie tabele z wyjątkiem Customers_Compress mają mniej więcej ten sam rozmiar. Teraz przebudujemy indeksy we wszystkich tabelach, wdrażając kompresję wierszy i stron odpowiednio w Customers_Row i Customers_Page.

ALTER INDEX ALL ON dbo.Customers REBUILD;
GO
ALTER INDEX ALL ON dbo.Customers_Page REBUILD WITH (DATA_COMPRESSION = PAGE);
GO
ALTER INDEX ALL ON dbo.Customers_Row REBUILD WITH (DATA_COMPRESSION = ROW);
GO
ALTER INDEX ALL ON dbo.Customers_Compress REBUILD;

Jeśli sprawdzimy rozmiar tabeli po kompresji, teraz możemy zobaczyć nasze oszczędności miejsca na dysku:

SELECT [o].[name], [i].[index_id], [i].[name], [p].[rows],  
(8*SUM([au].[used_pages]))/1024 AS [IndexSize(MB)], [p].[data_compression_desc]
FROM [sys].[allocation_units] [au]
JOIN [sys].[partitions] [p]
	ON [au].[container_id] = [p].[partition_id]
JOIN [sys].[objects] [o] 
	ON [p].[object_id] = [o].[object_id]
JOIN [sys].[indexes] [i]
	ON [p].[object_id] = [i].[object_id] AND [p].[index_id] = [i].[index_id]
WHERE [o].[is_ms_shipped] = 0
GROUP BY [o].[name], [i].[index_id], [i].[name], [p].[rows], [p].[data_compression_desc]
ORDER BY [i].[index_id], [IndexSize(MB)] DESC;


Rozmiar indeksu po kompresji

Zgodnie z oczekiwaniami kompresja wierszy i stron znacznie zmniejsza rozmiar tabeli i jej indeksów. Funkcja COMPRESS zaoszczędziła nam najwięcej miejsca – indeks klastrowy jest o jedną czwartą rozmiaru oryginalnej tabeli.

BADANIE WYDAJNOŚCI ZAPYTANIA

Zanim przetestujemy wydajność zapytań, zwróć uwagę, że możemy użyć Query Store do sprawdzenia wydajności INSERT i REBUILD:

SELECT [q].[query_id], [qt].[query_sql_text], 
SUM([rs].[count_executions]) [ExecutionCount], AVG([rs].[avg_duration])/1000 [AvgDuration_ms], 
AVG([rs].[avg_cpu_time]) [AvgCPU], AVG([rs].[avg_logical_io_reads]) [AvgLogicalReads], 
AVG([rs].[avg_physical_io_reads]) [AvgPhysicalReads]
FROM [sys].[query_store_query] [q]
JOIN [sys].[query_store_query_text] [qt] 
	ON [q].[query_text_id] = [qt].[query_text_id]
LEFT OUTER JOIN [sys].[objects] [o]
	ON [q].[object_id] = [o].[object_id]
JOIN [sys].[query_store_plan] [p]
	ON [q].[query_id] = [p].[query_id]
JOIN [sys].[query_store_runtime_stats] [rs]
	ON [p].[plan_id] = [rs].[plan_id]
WHERE [qt].[query_sql_text] LIKE '%INSERT%'
	OR [qt].[query_sql_text] LIKE '%ALTER%'
GROUP BY [q].[query_id], [q].[object_id], [o].[name], [qt].[query_sql_text], [rs].[plan_id]
ORDER BY [q].[query_id];

WSTAW i ODBUDUJ wskaźniki wydajności

Chociaż te dane są interesujące, bardziej ciekawi mnie, jak kompresja wpływa na moje codzienne zapytania SELECT. Mam zestaw trzech procedur przechowywanych, z których każda ma jedną kwerendę SELECT, dzięki czemu każdy indeks jest używany. Stworzyłem te procedury dla każdej tabeli, a następnie napisałem skrypt, który pobierał wartości imienia i nazwiska do testów. Oto skrypt do tworzenia procedur.

Po utworzeniu procedur składowanych możemy uruchomić poniższy skrypt, aby je wywołać. Rozpocznij i poczekaj kilka minut…

SET NOCOUNT ON;
GO
 
DECLARE @RowNum INT = 1;
DECLARE @Round INT = 1;
DECLARE @ID INT = 1;
DECLARE @FN NVARCHAR(64);
DECLARE @LN NVARCHAR(64);
DECLARE @SQLstring NVARCHAR(MAX);
 
DROP TABLE IF EXISTS #FirstNames, #LastNames;
 
SELECT  DISTINCT [FirstName], 
	DENSE_RANK() OVER (ORDER BY [FirstName]) AS RowNum
INTO #FirstNames
FROM [dbo].[Customers]
 
SELECT  DISTINCT [LastName], 
	DENSE_RANK() OVER (ORDER BY [LastName]) AS RowNum
INTO #LastNames
FROM [dbo].[Customers]
 
WHILE 1=1
BEGIN
	SELECT @FN = (
		SELECT [FirstName] 
		FROM #FirstNames
		WHERE RowNum = @RowNum)
 
	SELECT @LN = (
		SELECT [LastName] 
		FROM #LastNames
		WHERE RowNum = @RowNum)
 
	SET @FN = SUBSTRING(@FN, 1, 5) + '%'
 
	SET @LN = SUBSTRING(@LN, 1, 5) + '%'
 
	EXEC [dbo].[usp_FindActiveCustomer_C] @FN;
	EXEC [dbo].[usp_FindAnyCustomer_C] @LN;
	EXEC [dbo].[usp_FindSpecificCustomer_C] @ID;
	EXEC [dbo].[usp_FindActiveCustomer_P] @FN;
	EXEC [dbo].[usp_FindAnyCustomer_P] @LN;
	EXEC [dbo].[usp_FindSpecificCustomer_P] @ID;
	EXEC [dbo].[usp_FindActiveCustomer_R] @FN;
	EXEC [dbo].[usp_FindAnyCustomer_R] @LN;
	EXEC [dbo].[usp_FindSpecificCustomer_R] @ID;
	EXEC [dbo].[usp_FindActiveCustomer_CS] @FN;
	EXEC [dbo].[usp_FindAnyCustomer_CS] @LN;
	EXEC [dbo].[usp_FindSpecificCustomer_CS] @ID;
 
	IF @ID < 5000000
	BEGIN
		SET @ID = @ID + @Round
	END
	ELSE
	BEGIN
		SET @ID = 2
	END
 
	IF @Round < 26
	BEGIN
		SET @Round = @Round + 1
	END
	ELSE
	BEGIN
		IF @RowNum < 2260
		BEGIN
			SET @RowNum = @RowNum + 1
			SET @Round = 1
		END
		ELSE
		BEGIN
			SET @RowNum = 1
			SET @Round = 1
		END
	END
END
GO

Po kilku minutach spójrz na zawartość Query Store:

SELECT [q].[query_id], [q].[object_id], [o].[name], [qt].[query_sql_text], 
SUM([rs].[count_executions]) [ExecutionCount], CAST(AVG([rs].[avg_duration])/1000 AS DECIMAL(10,2)) [AvgDuration_ms], 
CAST(AVG([rs].[avg_cpu_time]) AS DECIMAL(10,2)) [AvgCPU], CAST(AVG([rs].[avg_logical_io_reads]) AS DECIMAL(10,2)) [AvgLogicalReads], 
CAST(AVG([rs].[avg_physical_io_reads]) AS DECIMAL(10,2)) [AvgPhysicalReads]
FROM [sys].[query_store_query] [q]
JOIN [sys].[query_store_query_text] [qt] 
	ON [q].[query_text_id] = [qt].[query_text_id]
JOIN [sys].[objects] [o]
	ON [q].[object_id] = [o].[object_id]
JOIN [sys].[query_store_plan] [p]
	ON [q].[query_id] = [p].[query_id]
JOIN [sys].[query_store_runtime_stats] [rs]
	ON [p].[plan_id] = [rs].[plan_id]
WHERE [q].[object_id] <> 0
GROUP BY [q].[query_id], [q].[object_id], [o].[name], [qt].[query_sql_text], [rs].[plan_id]
ORDER BY [o].[name];

Zobaczysz, że większość procedur składowanych została wykonana tylko 20 razy, ponieważ dwie procedury przeciwko [dbo].[Customers_Compress] są naprawdę powolny. To nie jest niespodzianka; ani [FirstName], ani [LastName] nie są indeksowane, więc każde zapytanie będzie musiało przeskanować tabelę. Nie chcę, aby te dwa zapytania spowalniały moje testowanie, więc zamierzam zmodyfikować obciążenie i skomentować EXEC [dbo].[usp_FindActiveCustomer_CS] i EXEC [dbo].[usp_FindAnyCustomer_CS], a następnie uruchomić go ponownie. Tym razem pozwolę mu działać przez około 10 minut, a kiedy ponownie spojrzę na dane wyjściowe Query Store, teraz mam dobre dane. Poniżej znajdują się surowe liczby, a poniżej wykresy ulubionych menedżerów.

Dane wydajności z magazynu zapytań

Czas trwania procedury składowanej

Procesor procedur zapisanych w bazie

Przypomnienie:Wszystkie procedury składowane, które kończą się na _C, pochodzą z tabeli nieskompresowanej. Procedury kończące się na _R to tabela skompresowana wierszami, te kończące się na _P są skompresowane na stronie, a ta z _CS używa funkcji COMPRESS (usunąłem wyniki dla tej tabeli dla usp_FindAnyCustomer_CS i usp_FindActiveCustomer_CS, ponieważ tak bardzo przekrzywiły wykres, że straciliśmy różnice w pozostałych danych). Procedury usp_FindAnyCustomer_* i usp_FindActiveCustomer_* wykorzystywały indeksy nieklastrowane i zwracały tysiące wierszy dla każdego wykonania.

Spodziewałem się, że czas trwania procedur usp_FindAnyCustomer_* i usp_FindActiveCustomer_* dla tabel skompresowanych wierszy i stron będzie dłuższy w porównaniu z tabelą nieskompresowaną, ze względu na obciążenie związane z dekompresją danych. Dane magazynu zapytań nie spełniają moich oczekiwań — czas trwania tych dwóch procedur składowanych jest mniej więcej taki sam (lub mniej w jednym przypadku!) w tych trzech tabelach. Logiczne operacje we/wy dla zapytań były prawie takie same we wszystkich tabelach nieskompresowanych oraz skompresowanych stron i wierszy.

Jeśli chodzi o procesor, w procedurach składowanych usp_FindActiveCustomer i usp_FindAnyCustomer był on zawsze wyższy dla skompresowanych tabel. Procesor był porównywalny dla procedury usp_FindSpecificCustomer, która zawsze była pojedynczym wyszukiwaniem w indeksie klastrowym. Zwróć uwagę na wysoki procesor (ale stosunkowo krótki czas trwania) dla procedury usp_FindSpecificCustomer względem tabeli [dbo].[Customer_Compress], która wymagała funkcji DECOMPRESS do wyświetlania danych w czytelnym formacie.

PODSUMOWANIE

Dodatkowy procesor wymagany do pobrania skompresowanych danych istnieje i można go zmierzyć za pomocą Query Store lub tradycyjnych metod określania wartości bazowych. W oparciu o te wstępne testy, procesor jest porównywalny dla wyszukiwań pojedynczych, ale rośnie wraz z większą ilością danych. Chciałem zmusić SQL Server do dekompresji więcej niż tylko 10 stron – chciałem co najmniej 100. Wykonałem wariacje tego skryptu, w którym zwrócono dziesiątki tysięcy wierszy, a wyniki były zgodne z tym, co tutaj widzisz. Oczekuję, że aby zobaczyć znaczne różnice w czasie trwania ze względu na czas potrzebny na dekompresję danych, zapytania musiałyby zwrócić setki tysięcy lub miliony wierszy. Jeśli pracujesz w systemie OLTP, nie chcesz zwracać tylu wierszy, więc testy tutaj powinny dać wyobrażenie o tym, jak kompresja może wpłynąć na wydajność. Jeśli jesteś w hurtowni danych, prawdopodobnie zobaczysz dłuższy czas trwania wraz z wyższym procesorem podczas zwracania dużych zestawów danych. Chociaż funkcja COMPRESS zapewnia znaczną oszczędność miejsca w porównaniu z kompresją stron i wierszy, spadek wydajności pod względem procesora oraz brak możliwości indeksowania skompresowanych kolumn ze względu na ich typ danych, sprawiają, że jest ona opłacalna tylko w przypadku dużych ilości danych, które nie zostaną wyszukiwane.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak wygenerować dane testowe DB

  2. Prosta parametryzacja i trywialne plany — część 2

  3. Używanie DBCC CLONEDATABASE i Query Store do testowania

  4. 8 poleceń WP-CLI do czyszczenia i optymalizacji witryny

  5. Przyrostowe maskowanie i mapowanie danych:wykrywanie zmian i aktualizowanie…