| Termin | Definicja |
|---|---|
| SqlDataReader | SqlDataReader to klasa .NET umożliwiająca szybki, jednokierunkowy odczyt wyników zapytania. SqlDataReader jako strumieniowy odczyt danychSqlDataReader jest elementem platformy .NET używanym do odczytywania rezultatów zapytań kierowanych do bazy Microsoft SQL Server. Jego działanie opiera się na odczycie sekwencyjnym: po wykonaniu polecenia można przechodzić przez kolejne rekordy w ustalonej kolejności, bez pobierania całego wyniku do pamięci aplikacji. Takie podejście dobrze sprawdza się wtedy, gdy zapytanie zwraca wiele wierszy, a dane mają być przetwarzane na bieżąco, na przykład podczas tworzenia listy, generowania zestawienia albo przekazywania informacji do kolejnego etapu programu. Obiekt tego typu jest zwykle tworzony przez połączenie z bazą danych oraz polecenie SQL. Po uruchomieniu polecenia otrzymuje się czytnik, który należy otworzyć, a następnie wywoływać metodę SqlDataReader nie jest kolekcją przechowującą wynik w formie swobodnie dostępnej tabeli. Po przejściu do następnego rekordu nie można traktować poprzedniego wiersza jak elementu listy, do którego da się wrócić w dowolnym momencie. Z tego powodu dane powinny być od razu mapowane do obiektu, przetwarzane, zapisywane w innym miejscu albo przekazywane do warstwy prezentacji. SqlDataReader a inne sposoby pobierania wynikówNajważniejszą cechą SqlDataReader jest jednokierunkowy charakter pracy. W porównaniu z mechanizmem, który tworzy w pamięci pełny zbiór wyników, czytnik zużywa mniej pamięci, ponieważ nie musi przechowywać wszystkich rekordów naraz. Ma to znaczenie przy większych zapytaniach, szczególnie gdy pojedynczy wiersz zawiera wiele pól albo dane są wykorzystywane stopniowo. Zyskiem może być również krótszy czas rozpoczęcia przetwarzania, ponieważ pierwszy rekord jest dostępny bez oczekiwania na zbudowanie kompletnej struktury po stronie aplikacji. Korzyść ta wiąże się jednak z ograniczeniami. Odczyt pozostaje powiązany z aktywnym połączeniem z bazą, dlatego połączenie nie powinno być zamykane przed zakończeniem przechodzenia przez rekordy. W czasie działania czytnika zasoby po stronie serwera oraz aplikacji są zajęte. Jeżeli potrzebne jest wielokrotne filtrowanie, sortowanie, przeskakiwanie między wierszami albo praca bez połączenia, lepszym rozwiązaniem może być wcześniejsze zapisanie danych do listy, tabeli danych lub własnych obiektów. W aplikacjach wykorzystujących programowanie asynchroniczne dostępne są także warianty odczytu niewstrzymujące głównego wątku. W takim modelu stosuje się między innymi Podczas projektowania zapytań należy również pamiętać o różnicy między parametrami a łączeniem tekstu. Parametryzowanie poleceń ułatwia bezpieczne przekazywanie wartości i ogranicza ryzyko nieprawidłowej interpretacji danych wejściowych. SqlDataReader odpowiada za odczyt rezultatu, ale nie zastępuje poprawnego budowania samego zapytania. SqlDataReader i typowe problemy w kodzieJednym z częstych błędów jest próba odczytania danych przed wykonaniem Problematyczne bywają także wartości Ostrożności wymaga również odczyt kolumn według indeksu. Zmiana kolejności pól w zapytaniu może wtedy spowodować przypisanie danych do niewłaściwych właściwości. Odczyt po nazwie jest bardziej czytelny i odporny na część takich zmian, choć może wymagać ustalenia nazw w sposób zgodny z rzeczywistym schematem zapytania. Przy częstym odczycie tych samych kolumn przydatne może być jednorazowe pobranie ich indeksów za pomocą Inny błąd polega na przetrzymywaniu czytnika zbyt długo. Jeżeli w trakcie iterowania wykonywane są dodatkowe, czasochłonne operacje, połączenie z bazą pozostaje zajęte przez cały ten okres. W razie potrzeby można ograniczyć zakres danych zapytaniem, pobierać tylko wymagane kolumny i szybko zamieniać rekordy na własne obiekty. Należy także unikać pobierania dużych pól, których aplikacja faktycznie nie wykorzystuje. Nie powinno się ignorować wyjątków związanych z połączeniem, przerwaniem zapytania, niezgodnością typów ani zamknięciem zasobu. Obsługa błędów powinna pozwalać na zapisanie informacji diagnostycznych bez ujawniania wrażliwych danych użytkownika. W przypadku pracy z transakcjami znaczenie ma również kolejność zamykania czytnika i kończenia transakcji, ponieważ otwarty odczyt może uniemożliwić dalsze działania na tym samym połączeniu. SqlDataReader w praktycznym użyciuPrzed rozpoczęciem odczytu warto ograniczyć wynik już na poziomie SQL. Selekcja konkretnych kolumn, zastosowanie właściwego warunku oraz pobieranie danych w logicznych partiach zmniejsza ilość informacji przesyłanych między bazą a aplikacją. Jeżeli wynik może być bardzo duży, przydatne bywa porcjowanie danych z użyciem odpowiedniej klauzuli, sortowania po stabilnym kluczu albo mechanizmu stronicowania dopasowanego do wersji silnika bazy. Mapowanie rekordu powinno być jednoznaczne. Dobrą praktyką jest wydzielenie fragmentu odpowiedzialnego za przekształcenie bieżącego wiersza w obiekt domenowy lub model transportowy. Dzięki temu logika związana z typami, wartościami pustymi i nazwami kolumn nie miesza się z obsługą interfejsu. Przydatne są metody takie jak Warto rozdzielić czas oczekiwania na bazę od czasu przetwarzania rekordu. Jeżeli pomiar obejmuje oba etapy jednocześnie, trudniej ustalić, czy przyczyną spowolnienia jest zapytanie, transfer danych, konwersja typów, zapis wyniku czy działanie interfejsu. Przydatne może być rejestrowanie czasu wykonania polecenia, liczby odczytanych wierszy oraz informacji o błędach. Dane diagnostyczne powinny być pozbawione haseł, pełnych danych osobowych i innych informacji, które nie są potrzebne do analizy. Przy pracy z dużymi tekstami lub obiektami binarnymi trzeba uwzględnić sposób ich pobierania. W niektórych zastosowaniach korzystniejsze jest odczytywanie fragmentów, aby nie tworzyć w pamięci aplikacji nadmiernych buforów. W innych przypadkach lepszym rozwiązaniem będzie przechowywanie plików poza tabelą i zapisywanie w bazie jedynie metadanych. Decyzję należy oprzeć na rozmiarze danych, sposobie dostępu, wymaganiach kopii zapasowych i oczekiwanej wydajności. SqlDataReader i moment zgłoszenia problemuWsparcie techniczne może być potrzebne, gdy aplikacja zaczyna zużywać dużo pamięci mimo korzystania z czytnika, połączenia pozostają otwarte, zapytania wykonują się coraz dłużej albo pojawiają się błędy dotyczące zamkniętych zasobów. Zgłoszenie jest również zasadne wtedy, gdy po zmianie struktury tabeli dane trafiają do nieprawidłowych pól, wartości puste powodują wyjątki lub aplikacja działa poprawnie tylko dla małych wyników. W ramach Warszawskiego Pogotowia Komputerowego 24/7 można skonsultować problemy z działaniem komputera, aplikacji oraz połączeń wykorzystywanych przy pracy z bazą danych. Do przygotowania diagnozy pomocne są komunikat błędu, fragment logu bez danych poufnych, informacja o wersji środowiska .NET, opis wykonywanego zapytania oraz wskazanie, czy problem występuje stale, czy tylko przy większej liczbie rekordów. Takie materiały ułatwiają odróżnienie błędu w kodzie od problemu z konfiguracją, zasobami systemu lub samą bazą. Przed przekazaniem sprzętu lub środowiska do analizy warto wykonać kopię ważnych danych i zanotować ostatnie zmiany, takie jak aktualizacja systemu, sterowników, aplikacji albo konfiguracji połączenia. Nie należy przekazywać haseł zapisanych w kodzie ani plików zawierających pełne dane klientów. W wielu przypadkach wystarcza bezpiecznie przygotowany opis, zanonimizowany fragment projektu oraz powtarzalny przykład problemu. Dzięki temu można szybciej ustalić, czy konieczna jest korekta obsługi SqlDataReader, zmiana zapytania, poprawa zwalniania zasobów czy szersza diagnostyka komputera. |