- Wiersz opisuje stan sesji pulpitu zdalnego: kiedy się zaczęła, jak długo trwała bezczynność i kiedy została zamknięta.
- Zapis obejmuje dane stanowiska klienckiego — nazwę komputera, rozdzielczość i dwa adresy IP: lokalny oraz publiczny.
- Kolumna
IDLETIMEpozwala odróżnić sesję aktywną od porzuconej, która wciąż zajmuje zasoby serwera. - Tabela ma dziewięć indeksów, w tym dwa obejmujące niemal wszystkie kolumny — to przypadek wart osobnego omówienia.
Do czego służy tabela [dbo].[_sessionlog]
Gdy aplikacja jest udostępniana przez pulpit zdalny, obciążenie serwera zależy nie od liczby zatrudnionych, lecz od liczby sesji utrzymywanych jednocześnie. Tabela [dbo].[_sessionlog] gromadzi dane pozwalające to zmierzyć: momenty połączenia, rozłączenia i ostatniej aktywności, a także stan każdej sesji.
Zakres zapisywanych informacji sięga poza serwer. Nazwa komputera klienckiego, jego rozdzielczość, numer kompilacji klienta oraz dwa adresy IP — lokalny i publiczny — pozwalają ustalić, skąd faktycznie łączy się użytkownik. Rozróżnienie obu adresów ma praktyczne znaczenie: pokazuje, czy połączenie idzie z sieci firmowej, czy z zewnątrz.
Najbardziej użyteczną kolumną w codziennej pracy jest IDLETIME, czyli czas bezczynności w minutach. To on odróżnia sesję, w której ktoś pracuje, od pozostawionej na noc — a ta druga zajmuje pamięć serwera i, jeżeli licencja liczona jest stanowiskami, blokuje dostęp komuś innemu.
Sesja rozłączona nie jest tym samym co zamknięta — pozostaje na serwerze i zwalnia zasoby dopiero po wygaśnięciu limitu czasu.
Budowa tabeli — wykaz kolumn
Dwadzieścia dwie kolumny opisują sesję w trzech wymiarach: kto i skąd się łączy, kiedy oraz w jakim jest stanie.
| Kolumna | Typ | Wymagana | Znaczenie |
|---|---|---|---|
| Użytkownik i serwer | |||
ID_LOG | int liczba całkowita | tak | Unikalny identyfikator logu sesji |
SESSIONID | int liczba całkowita | tak | Unikalny identyfikator sesji |
USERNAME | varchar(50) tekst do 50 znaków | nie | Nazwa użytkownika sesji |
USERACCOUNT | varchar(100) tekst do 100 znaków | nie | Konto użytkownika w domenie lub na serwerze |
DOMAINNAME | varchar(50) tekst do 50 znaków | nie | Nazwa domeny użytkownika |
SERVER | varchar(15) tekst do 15 znaków | nie | Nazwa serwera, na którym odbywała się sesja |
WINDOWSSTATIONNAME | varchar(100) tekst do 100 znaków | nie | Nazwa stacji roboczej Windows używanej przez użytkownika |
| Stanowisko klienckie | |||
CLIENTNAME | varchar(15) tekst do 15 znaków | nie | Nazwa komputera klienckiego |
CLIENTIPADRESS | varchar(50) tekst do 50 znaków | nie | Adres IP klienta sesji RDP |
CLIENTREMOTEIPADRESS | varchar(50) tekst do 50 znaków | nie | Publiczny adres IP klienta sesji RDP |
CLIENTDISPLAY | varchar(250) tekst do 250 znaków | nie | Rozdzielczość ekranu klienta sesji RDP |
CLIENTBUILDNUMBER | int liczba całkowita | nie | Numer kompilacji klienta RDP |
| Czasy i stan sesji | |||
LOGINTIME | datetime data i godzina | nie | Data i czas logowania użytkownika do sesji |
CONNECTTIME | datetime data i godzina | nie | Data i czas nawiązania połączenia sesji |
DISCONNECTTIME | datetime data i godzina | nie | Data i czas rozłączenia sesji |
LASTINPUTTIME | datetime data i godzina | nie | Data i czas ostatniej aktywności użytkownika |
CURRENTTIME | datetime data i godzina | nie | Aktualny czas rekordu sesji |
IDLETIME | float liczba zmiennoprzecinkowa | nie | Czas bezczynności sesji, mierzony w minutach |
CONNECTIONSTATE | varchar(20) tekst do 20 znaków | nie | Stan połączenia sesji (np. Aktywna, Rozłączona) |
SESSIONCHANGERESON | varchar(50) tekst do 50 znaków | tak | Przyczyna zmiany stanu sesji |
KIEDY | datetime data i godzina | tak | Data i czas, kiedy rekord został dodany do bazy danych |
TIMESTAMP | timestamp znacznik wersji wiersza | tak | Znacznik czasu aktualizacji rekordu |
Kolumna IDLETIME ma typ float i podaje czas bezczynności w minutach. Warto porównywać ją z LASTINPUTTIME — rozbieżność między nimi wskazuje, że rekord sesji nie był ostatnio odświeżany.
Indeksy i wydajność zapytań
Zestaw indeksów tej tabeli jest nietypowy i zasługuje na komentarz, bo pokazuje problem spotykany w wielu bazach produkcyjnych.
| Indeks | Kolumny | Rodzaj |
|---|---|---|
CONNECTTIME_SERVER_USERNAME | CONNECTTIME, SERVER, USERNAME, KIEDY | zwykły |
DISCONECTTIME_USERNAME_KIEDY | ID_LOG, CLIENTBUILDNUMBER, CLIENTDISPLAY, CLIENTIPADRESS, CLIENTNAME, CONNECTIONSTATE, CONNECTTIME, CURRENTTIME, DOMAINNAME, IDLETIME, LASTINPUTTIME, LOGINTIME, SERVER, USERACCOUNT, WINDOWSSTATIONNAME, SESSIONID, SESSIONCHANGERESON, TIMESTAMP, CLIENTREMOTEIPADRESS, DISCONNECTTIME, USERNAME, KIEDY | zwykły |
KIEDY | CONNECTTIME, IDLETIME, SERVER, USERNAME, KIEDY | zwykły |
PK__sessionlog | ID_LOG | klucz główny |
SESSIONCHANGERESON | SESSIONCHANGERESON | zwykły |
USERNAME | CONNECTTIME, CURRENTTIME, IDLETIME, LASTINPUTTIME, SERVER, SESSIONID, USERNAME | zwykły |
USERNAME_CONNECTTIME_CURRENTTIME_IDLETIME_LASTINPUTTIME_SERVER_SESSIONID | CONNECTTIME, CURRENTTIME, IDLETIME, LASTINPUTTIME, SERVER, SESSIONID, USERNAME | zwykły |
USERNAME_DISCONECTTIME_LOGINTIME | DISCONNECTTIME, LOGINTIME, USERNAME | zwykły |
USERNAME_KIEDY_DISCONECTTIME | ID_LOG, CLIENTBUILDNUMBER, CLIENTDISPLAY, CLIENTIPADRESS, CLIENTNAME, CONNECTIONSTATE, CONNECTTIME, CURRENTTIME, DOMAINNAME, IDLETIME, LASTINPUTTIME, LOGINTIME, SERVER, USERACCOUNT, WINDOWSSTATIONNAME, SESSIONID, SESSIONCHANGERESON, TIMESTAMP, CLIENTREMOTEIPADRESS, USERNAME, KIEDY, DISCONNECTTIME | zwykły |
Dwa z dziewięciu indeksów obejmują niemal wszystkie kolumny tabeli. Taki indeks jest w praktyce drugą kopią danych: podwaja miejsce zajmowane przez tabelę, wydłuża każdy zapis i musi być aktualizowany przy każdej zmianie stanu sesji. Kilka pozostałych pokrywa się zakresem — na przykład USERNAME i USERNAME_CONNECTTIME_CURRENTTIME_IDLETIME_LASTINPUTTIME_SERVER_SESSIONID obejmują dokładnie ten sam zestaw kolumn.
Nadmiar indeksów — jak powstaje i co kosztuje
Indeksy tej tabeli są dobrym przykładem procesu, który przebiega niemal identycznie w każdej bazie rozwijanej przez kilka lat.
| Obszar | Wpływ indeksu | Kiedy się opłaca |
|---|---|---|
| Odczyt zapytania wzorcowego | Skrócenie czasu, czasem wielokrotne | Zapytanie wykonywane często |
| Zapis wiersza | Każdy indeks musi zostać zaktualizowany | Tabela odczytywana częściej niż zapisywana |
| Miejsce na dysku | Indeks obejmujący wszystkie kolumny podwaja rozmiar tabeli | Nigdy — to sygnał błędu projektowego |
| Kopia zapasowa | Dłuższy czas wykonania i odtworzenia | Gdy korzyść z odczytu przewyższa koszt |
| Plan wykonania | Optymalizator wybiera spośród większej liczby wariantów | Przy nielicznych, wyraźnie różnych indeksach |
Ostatni wiersz bywa pomijany: przy kilkunastu podobnych indeksach serwer częściej wybiera nieoptymalny wariant, niż gdyby miał ich trzy.
Mechanizm powstawania jest zawsze ten sam. Pojawia się wolne zapytanie, ktoś zakłada indeks pod nie, problem znika. Po pół roku pojawia się kolejne, nieco inne — powstaje kolejny indeks, częściowo pokrywający się z poprzednim. Nikt nie usuwa starych, bo nie ma pewności, czy nie są używane. SQL Server udostępnia widoki systemowe pokazujące, ile razy każdy indeks został faktycznie wykorzystany od ostatniego restartu — i to od nich warto zacząć porządki, zamiast zgadywać.
Jak korzystać z tabeli w praktyce
Przy analizie sesji i utrzymaniu tej tabeli warto pamiętać o kilku sprawach:
- Odróżniaj sesję rozłączoną od zamkniętej — pierwsza nadal zajmuje zasoby serwera aż do wygaśnięcia limitu czasu.
- Korzystaj z kolumny
IDLETIMEprzy ustalaniu limitu bezczynności; rozkład jej wartości pokazuje, jak faktycznie pracują użytkownicy. - Porównuj
CLIENTIPADRESSzCLIENTREMOTEIPADRESS, żeby odróżnić połączenia z sieci firmowej od zewnętrznych. - Przed usunięciem któregokolwiek indeksu sprawdź w widokach systemowych, czy jest używany — zgadywanie kończy się przywracaniem go tydzień później.
- Archiwizuj wpisy starsze niż kilka miesięcy; przy dziewięciu indeksach objętość rośnie znacznie szybciej niż same dane.
- Zestawiaj liczbę sesji równoległych z liczbą stanowisk licencyjnych — to najprostsza kontrola zgodności z umową.
Sesje bezczynne dłużej niż dwie godziny, wciąż utrzymywane na serwerze — kandydaci do zamknięcia:
SELECT USERNAME,
SERVER,
CLIENTNAME,
CONNECTIONSTATE,
CONNECTTIME,
LASTINPUTTIME,
CAST(IDLETIME AS int) AS BEZCZYNNOSC_MIN
FROM dbo._sessionlog
WHERE DISCONNECTTIME IS NULL
AND IDLETIME > 120
ORDER BY IDLETIME DESC;
Przed zamknięciem sesji warto sprawdzić kolumnę CONNECTIONSTATE — sesja rozłączona bywa świadomie pozostawiona przez użytkownika pracującego zdalnie z przerwami.
Rejestr sesji odpowiada na pytania, których nie zada się danym operacyjnym: ilu ludzi faktycznie pracuje w szczycie, ile sesji wisi bez celu i skąd łączą się użytkownicy. Przy okazji pokazuje, jak łatwo baza obrasta w indeksy, których nikt już nie potrafi uzasadnić.
Powiązane tabele i dokumentacja
Rejestr sesji uzupełnia pozostałe zapisy dotyczące dostępu i wykorzystania systemu: