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 dofor
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.