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

Zawsze szyfrowana wydajność:kontynuacja

W zeszłym tygodniu pisałem o ograniczeniach Always Encrypted, a także o wpływie na wydajność. Chciałem opublikować kontynuację po przeprowadzeniu dalszych testów, głównie ze względu na następujące zmiany:

  • Dodałem test dla lokalnego, aby sprawdzić, czy obciążenie sieci jest znaczące (wcześniej test był tylko zdalny). Chociaż powinienem umieścić „narzut sieci” w cytatach z powietrza, ponieważ są to dwie maszyny wirtualne na tym samym hoście fizycznym, więc nie jest to prawdziwa analiza bare metal.
  • Dodałem kilka dodatkowych (niezaszyfrowanych) kolumn do tabeli, aby uczynić ją bardziej realistyczną (ale nie aż tak realistyczną).
     DateCreated DATETIME NOT NULL DEFAULT SYSUTCDATETIME(), DateModified DATETIME NOT NULL DEFAULT SYSUTCDATETIME() , Aktywny BIT NIE JEST NULL DOMYŚLNY 1

    Następnie odpowiednio zmieniono procedurę pobierania:

    ZMIANA PROCEDURY dbo.RetrievePeopleASBEGIN USTAW NOCOUNT ON; SELECT TOP (100) LastName, Salary, DateCreated, DateModified, Active FROM dbo.Employees ORDER BY NEWID();ENDGO
  • Dodano procedurę obcinania tabeli (wcześniej robiłem to ręcznie między testami):
    CREATE PROCEDURE dbo.CleanupASBEGIN SET NOCOUNT ON; OBCIĄŻ TABELĘ dbo.Employees;ENDGO
  • Dodano procedurę rejestrowania czasów (wcześniej ręcznie analizowałem dane wyjściowe konsoli):
    USE Utility;GO CREATE TABLE dbo.Timings(Test NVARCHAR(32), InsertTime INT, SelectTime INT, TestCompleted DATETIME NOT NULL DEFAULT SYSUTCDATETIME (), nazwa hosta SYSNAME NOT NULL DEFAULT HOST_NAME());GO CREATE PROCEDURE dbo.AddTiming @Test VARCHAR(32), @InsertTime INT, @SelectTime INTASBEGIN SET NOCOUNT ON; INSERT dbo.Timings(Test,InsertTime,SelectTime) SELECT @Test,@InsertTime,@SelectTime;ENDGO
  • Dodałem parę baz danych, które wykorzystywały kompresję stron – wszyscy wiemy, że zaszyfrowane wartości nie kompresują się dobrze, ale jest to funkcja polaryzacyjna, której można użyć jednostronnie nawet w przypadku tabel z zaszyfrowanymi kolumnami, więc pomyślałem, że po prostu profil te też. (I dodano jeszcze dwa parametry połączenia do App.Config .)
        
  • Wprowadziłem wiele ulepszeń do kodu C# (patrz załącznik) na podstawie opinii Tobi (co doprowadziło do tego pytania w sprawie przeglądu kodu) i wspaniałej pomocy współpracownika Brooke Philpott (@Macromullet). Należą do nich:
    • wyeliminowanie procedury składowanej do generowania losowych nazwisk/wynagrodzeń i zrobienie tego w C#
    • za pomocą Stopwatch zamiast niezdarnych ciągów daty/godziny
    • bardziej spójne korzystanie z using() i eliminacja .Close()
    • nieco lepsze konwencje nazewnictwa (i komentarze!)
    • zmiana while pętle do for pętle
    • za pomocą StringBuilder zamiast naiwnej konkatenacji (którą początkowo wybrałem celowo)
    • konsolidacja parametrów połączenia (chociaż nadal celowo tworzę nowe połączenie w każdej iteracji pętli)

Następnie utworzyłem prosty plik wsadowy, który uruchamiałby każdy test 5 razy (i powtórzyłem to zarówno na komputerze lokalnym, jak i zdalnym):

dla /l %%x w (1,1,5) do ( ^AEDemoConsole "Normal" &^AEDemoConsole "Encrypt" &^AEDemoConsole "NormalCompress" &^AEDemoConsole "EncryptCompress" &^)

Po zakończeniu testów zmierzenie czasu trwania i wykorzystanej przestrzeni byłoby trywialne (a budowanie wykresów na podstawie wyników wymagałoby tylko niewielkiej manipulacji w Excelu):

-- czas trwania SELECT Nazwa hosta, Test, CzasWstawiania =AVG(1.0*CzasWstawiania), CzasWybierania =AVG(1,0*CzasWybierania)FROM Utility.dbo.TimingsGROUP BY HostName, TestORDER BY HostName, Test; -- spacja USE Normalna; -- Normalna kompresja; Szyfruj; SzyfrujKompres; SELECT COUNT(*)*8.192 FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID(N'dbo.Pracownicy'), NULL, NULL, N'LIMITED');

Wyniki czasu trwania

Oto nieprzetworzone wyniki z powyższego zapytania o czas trwania (CANUCK to nazwa maszyny, na której znajduje się instancja SQL Server, a HOSER to maszyna, która uruchomiła zdalną wersję kodu):

Nieprzetworzone wyniki zapytania o czas trwania

Oczywiście łatwiej będzie wizualizować w innej formie. Jak pokazano na pierwszym wykresie, zdalny dostęp miał znaczący wpływ na czas trwania wkładek (wzrost o ponad 40%), ale kompresja miała w ogóle niewielki wpływ. Samo szyfrowanie w przybliżeniu podwoiło czas trwania dowolnej kategorii testów:

Czas (milisekundy) na wstawienie 100 000 wierszy

W przypadku odczytów kompresja miała znacznie większy wpływ na wydajność niż szyfrowanie lub zdalny odczyt danych:

Czas (w milisekundach) 1000 razy odczytania 100 losowych wierszy

Wyniki w kosmosie

Jak można było przewidzieć, kompresja może znacznie zmniejszyć ilość miejsca wymaganego do przechowywania tych danych (mniej więcej o połowę), podczas gdy szyfrowanie może wpływać na rozmiar danych w przeciwnym kierunku (prawie trzykrotnie). I oczywiście kompresowanie zaszyfrowanych wartości się nie opłaca:

Miejsce używane (KB) do przechowywania 100 000 wierszy z kompresją lub bez oraz z kompresją lub bez szyfrowanie

Podsumowanie

Powinno to dać ogólne pojęcie o tym, czego można się spodziewać po wdrożeniu Always Encrypted. Pamiętaj jednak, że był to bardzo szczególny test i że używałem wczesnej wersji CTP. Twoje dane i wzorce dostępu mogą dawać bardzo różne wyniki, a dalsze postępy w przyszłych CTP i aktualizacjach .NET Framework mogą zmniejszyć niektóre z tych różnic nawet w tym samym teście.

Zauważysz również, że wyniki tutaj były nieco inne niż w moim poprzednim poście. Można to wyjaśnić:

  • Czasy wstawiania były szybsze we wszystkich przypadkach, ponieważ nie ponoszę już dodatkowej podróży w obie strony do bazy danych, aby wygenerować losowe imię i pensję.
  • Wybrane czasy były we wszystkich przypadkach szybsze, ponieważ nie używam już niechlujnej metody łączenia ciągów (która była częścią metryki czasu trwania).
  • Wykorzystana przestrzeń była nieco większa w obu przypadkach, podejrzewam, że z powodu innego rozkładu losowych ciągów, które zostały wygenerowane.

Dodatek A – Kod aplikacji konsoli C#

używanie System;używanie System.Configuration;używanie System.Text;używanie System.Data;używanie System.Data.SqlClient; namespace AEDemo{ class AEDemo { static void Main(string[] args) { // ustawienie stopera do pomiaru czasu każdej części kodu var timer =System.Diagnostics.Stopwatch.StartNew(); // losowy obiekt dostarczający losowe nazwiska/pensje var random =new Random(); // połącz na podstawie argumentu wiersza polecenia var connectionString =ConfigurationManager.ConnectionStrings[args[0]].ToString(); using (var sqlConnection =new SqlConnection(connectionString)) { // to po prostu obcina tabelę, co wcześniej robiłem ręcznie, używając (var sqlCommand =new SqlCommand("dbo.Cleanup", sqlConnection)) { sqlConnection.Open(); sqlCommand.ExecuteNonQuery(); } } // najpierw wygeneruj 100 000 par imię/pensja i wstaw je dla (int i =1; i <=100000; i++) { // random pensja między 32750 a 19500 var randomSalary =random.Next(32750, 19500); // losowy ciąg losowej liczby znaków var length =random.Next(1, 32); char[] randomCharArray =nowy char[długość]; for (int byteOffset =0; byteOffset
  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ScaleGrid podnosi rundę wzrostu kapitału od partnerów Spotlight Equity w celu przyspieszenia ekspansji i dalszych inwestycji w plan rozwoju produktów

  2. CREATE TABLE w SQL – wszystko, co musisz wiedzieć o tworzeniu tabel w SQL

  3. Widoki SQL

  4. Tabela rozwiązywania problemów Nie znaleziono błędów

  5. RMAN nie działa z RMAN-06900 RMAN-06901 ORA-04031