Access
 sql >> Baza danych >  >> RDS >> Access

Jak program Access komunikuje się ze źródłami danych ODBC? Część 5

Filtrowanie zestawu rekordów

W części 5 naszej serii dowiemy się, jak Microsoft Access obsługuje zaimplementowane filtry i integruje je z zapytaniami ODBC. W poprzednim artykule widzieliśmy, jak program Access formułuje SELECT instrukcji w poleceniach ODBC SQL. W poprzednim artykule widzieliśmy również, jak program Access próbuje zaktualizować wiersz, stosując znacznik WHERE klauzula oparta na kluczu i, jeśli ma to zastosowanie, rowversion. Musimy jednak dowiedzieć się, jak Access będzie obsługiwał filtry dostarczane do zapytań Access i przetłumaczy je na warstwę ODBC. Istnieją różne podejścia, które program Access może stosować w zależności od tego, jak sformułowane są zapytania programu Access, i dowiesz się, jak przewidzieć, w jaki sposób program Access przetłumaczy zapytanie programu Access na zapytanie ODBC dla różnych podanych predykatów filtra.

Niezależnie od tego, w jaki sposób faktycznie zastosujesz filtr — czy to interaktywnie za pomocą poleceń na wstążce formularza lub arkusza danych lub kliknięć w prawym menu, czy też programowo przy użyciu języka VBA lub uruchamiając zapisane zapytania — program Access wyśle ​​odpowiednie zapytanie SQL ODBC w celu przeprowadzenia filtrowania. Ogólnie rzecz biorąc, program Access będzie próbował maksymalnie przeprowadzić zdalne filtrowanie. Jednak nie powie ci, jeśli nie może tego zrobić. Zamiast tego, jeśli program Access nie może wyrazić filtru przy użyciu składni ODBC SQL, zamiast tego spróbuje przeprowadzić samo filtrowanie, pobierając całą zawartość tabeli i lokalnie oceniając warunek. To może wyjaśniać, dlaczego czasami możesz napotkać zapytanie, które działa szybko, ale z jedną niewielką zmianą, spowalnia do indeksowania. Mamy nadzieję, że ta sekcja pomoże ci zrozumieć, kiedy może się to zdarzyć i jak sobie z tym poradzić, aby w jak największym stopniu pomóc w zdalnym dostępie do źródeł danych w celu zastosowania filtra.

W tym artykule użyjemy zapisanych zapytań, ale omówione tutaj informacje powinny nadal dotyczyć innych metod stosowania filtrów.

Filtry statyczne

Zaczniemy łatwo i utworzymy zapisane zapytanie z zakodowanym na stałe filtrem.

SELECT 
   c.CityID
  ,c.CityName
  ,c.StateProvinceID
FROM Cities AS c
WHERE c.CityName="Boston";
Jeśli otworzymy zapytanie, w śladzie zobaczymy ten kod SQL ODBC:

SQLExecDirect: 
SELECT "c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ("CityName" = 'Boston' ) 
Oprócz zmian w składni, semantyka zapytania nie uległa zmianie; ten sam filtr jest przekazywany w stanie, w jakim jest. Zwróć uwagę, że tylko CityID została wybrana, ponieważ domyślnie zapytanie używa zestawu rekordów typu dynaset, o którym mówiliśmy już w poprzedniej sekcji.

Proste filtry parametryczne

Zmieńmy SQL, aby zamiast tego używał parametru:

PARAMETERS SelectedCityName Text ( 255 );
SELECT 
  c.CityID
 ,c.CityName
 ,c.StateProvinceID
FROM Cities AS c
WHERE c.CityName=[SelectedCityName];
Jeśli uruchomimy zapytanie i wprowadzimy „Boston” do wartości monitu o parametr, jak pokazano, powinniśmy zobaczyć następujący kod SQL śledzenia ODBC:
SQLExecDirect: 
SELECT "c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ("CityName" =  ? ) 
Zauważ, że będziemy zaobserwować to samo zachowanie w przypadku odwołań do kontrolek lub łączenia podformularzy. Jeśli zamiast tego użyjemy tego:

SELECT 
   c.CityID
  ,c.CityName
  ,c.StateProvinceID
FROM Cities AS c
WHERE c.CityName=[Forms]![frmSomeForm]![txtSomeText];
Nadal otrzymalibyśmy ten sam prześledzony kod SQL ODBC, który widzieliśmy w oryginalnym zapytaniu parametrycznym. Nadal tak jest, mimo że nasze zmodyfikowane zapytanie nie miało PARAMETERS oświadczenie. To pokazuje, że Access jest w stanie rozpoznać, że takie odwołania kontrolne, których wartość może się zmieniać od czasu do czasu, najlepiej traktować jako parametr podczas formułowania SQL ODBC.

Działa to również w przypadku funkcji VBA. Możemy dodać nową funkcję VBA:

Public Function GetSelectedCity() As String
    GetSelectedCity = "Boston"
End Function
Dostosowujemy zapisane zapytanie, aby korzystało z nowej funkcji VBA:

WHERE c.CityName=GetSelectedCity();
Jeśli to prześledzisz, zobaczysz, że nadal jest tak samo. W ten sposób wykazaliśmy, że niezależnie od tego, czy dane wejściowe są jawnym parametrem, odwołaniem do kontrolki, czy wynikiem funkcji VBA, program Access potraktuje je wszystkie jako parametr zapytania ODBC SQL, które wykona na naszym w imieniu. To dobrze, ponieważ generalnie uzyskujemy lepszą wydajność, gdy możemy ponownie użyć zapytania i po prostu zmienić parametr.

Istnieje jednak jeszcze jeden typowy scenariusz, który programiści programu Access zwykle konfigurują i polega na tworzeniu dynamicznego kodu SQL z kodem VBA, zwykle przez połączenie ciągu, a następnie wykonanie połączonego ciągu. Użyjmy następującego kodu VBA:

Public Sub GetSelectedCities()
    Dim db As DAO.Database
    Dim rs As DAO.Recordset
    Dim fld As DAO.Field
    
    Dim SelectedCity As String
    Dim SQLStatement As String
    
    SelectedCity = InputBox("Enter a city name")
    SQLStatement = _
        "SELECT c.CityID, c.CityName, c.StateProvinceID " & _
        "FROM Cities AS c " & _
        "WHERE c.CityName = '" & SelectedCity & "';"
    
    Set db = CurrentDb
    Set rs = db.OpenRecordset(SQLStatement)
    Do Until rs.EOF
        For Each fld In rs.Fields
            Debug.Print fld.Value;
        Next
        Debug.Print
        rs.MoveNext
    Loop
End Sub
Śledzony SQL ODBC dla OpenRecordset wygląda następująco:

SQLExecDirect: 
SELECT "c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ("CityName" = 'Boston' ) 
W przeciwieństwie do poprzednich przykładów, SQL ODBC nie był sparametryzowany. Access nie ma możliwości dowiedzenia się, że „Boston” został dynamicznie zapełniony w czasie wykonywania przez VBA.InputBox . Po prostu przekazaliśmy mu skonstruowany SQL, który z POV Accessa jest po prostu statyczną instrukcją SQL. W takim przypadku pokonujemy parametryzację zapytania. Należy pamiętać, że popularną radą udzielaną programistom Access jest to, że dynamicznie konstruowany SQL jest lepszy niż używanie zapytań parametrycznych, ponieważ pozwala uniknąć problemu polegającego na tym, że silnik Access może generować plan wykonania na podstawie jednej wartości parametru, która może być w rzeczywistości nieoptymalna dla innej wartość parametru. Po więcej szczegółów na temat tego zjawiska zachęcam do lektury problemu „podsłuchiwania parametrów”. Zwróć uwagę, że jest to ogólny problem dotyczący wszystkich aparatów baz danych, nie tylko programu Access. Jednak w przypadku Accessa dynamiczny SQL działał lepiej, ponieważ znacznie taniej jest samo wygenerowanie nowego planu wykonania. W przeciwieństwie do tego, silnik RDBMS może mieć dodatkowe strategie radzenia sobie z problemem i może być bardziej wrażliwy na posiadanie zbyt wielu jednorazowych planów wykonania, ponieważ może to negatywnie wpłynąć na jego buforowanie.

Z tego powodu zapytania parametryczne z programu Access do źródeł ODBC mogą być preferowane w porównaniu z dynamicznym SQL. Ponieważ program Access będzie traktował kontrolki odwołań w formularzu lub funkcjach VBA, które nie wymagają odwołań do kolumn jako parametry, nie potrzebujesz jawnych parametrów w źródłach rekordów ani źródłach wierszy. Jeśli jednak używasz VBA do wykonywania SQL, zwykle lepiej jest użyć ADO, które ma również znacznie lepszą obsługę parametryzacji. W przypadku budowania dynamicznego źródła rekordów lub źródła wierszy użycie ukrytej kontrolki w formularzu/raporcie może być łatwym sposobem na parametryzację zapytania. Jeśli jednak zapytanie jest znacznie inne, budowanie dynamicznego kodu SQL w języku VBA i przypisanie go do właściwości źródła rekordów/rowsource skutecznie wymusza pełną ponowną kompilację, a tym samym unika używania złych planów wykonania, które nie będą działać dobrze dla bieżącego zestawu danych wejściowych. Zalecenia można znaleźć w artykule omawiającym WITH RECOMPILE programu SQL Server pomocne przy podejmowaniu decyzji, czy wymusić ponowną kompilację, czy użyć sparametryzowanego zapytania.

Korzystanie z funkcji w filtrowaniu SQL

W poprzedniej sekcji widzieliśmy, że instrukcja SQL zawierająca funkcję VBA została sparametryzowana, aby program Access mógł wykonać funkcję VBA i wykorzystać dane wyjściowe jako dane wejściowe do sparametryzowanego zapytania. Jednak nie wszystkie wbudowane funkcje zachowują się w ten sposób. Użyjmy UCase() jako przykład do filtrowania zapytania. Ponadto zastosujemy tę funkcję do kolumny.

SELECT 
   c.CityID
  ,c.CityName
  ,c.StateProvinceID
FROM Cities AS c
WHERE UCase([c].[CityName])="BOSTON";
Jeśli spojrzymy na śledzony SQL ODBC, zobaczymy to:

SQLExecDirect: 
SELECT "c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ({fn ucase("CityName" )}= 'BOSTON' )
W poprzednim przykładzie program Access był w stanie całkowicie sparametryzować GetSelectedCity() ponieważ nie wymagało to żadnych danych wejściowych z kolumn, do których odwołuje się zapytanie. Jednak UCase() wymaga danych wejściowych. Czy udostępniliśmy UCase("Boston") , Access również sparametryzowałby to. Jednak dane wejściowe to odwołanie do kolumny, którego program Access nie może łatwo sparametryzować. Program Access może jednak wykryć, że UCase() jest jedną z obsługiwanych funkcji skalarnych ODBC. Ponieważ wolimy jak najwięcej zdalnych połączeń od źródła danych, Access robi to właśnie, wywołując wersję ucase ODBC .

Jeśli następnie utworzymy niestandardową funkcję VBA, która emuluje UCase() funkcja:

Public Function MyUCase(InputValue As Variant) As String
    MyUCase = UCase(InputValue)
End Function
i zmieniłem filtrowanie w zapytaniu na:

WHERE MyUCase([c].[CityName])="BOSTON";
Oto, co otrzymujemy:

SQLExecDirect: 
SELECT 
   "CityName"
  ,"c"."CityID" 
FROM "Application"."Cities" "c" 
Access nie może zdalnie użyć niestandardowej funkcji VBA MyUCase z powrotem do źródła danych. Jednak SQL zapisanego zapytania jest legalny, więc Access musi go jakoś spełnić. Aby to zrobić, kończy się pobraniem pełnego zestawu CityName i odpowiadający mu CityID w celu przejścia do funkcji VBA MyUCase() i oceń wynik. W związku z tym zapytanie działa teraz znacznie wolniej, ponieważ program Access żąda teraz większej ilości danych i wykonuje więcej pracy.

Chociaż użyliśmy UCase() w tym przykładzie wyraźnie widzimy, że generalnie lepiej jest wykonywać jak najwięcej pracy zdalnej do źródła danych. Ale co, jeśli mamy złożoną funkcję VBA, której nie można przepisać w natywnym dialekcie SQL źródła danych? Chociaż uważam, że ten scenariusz jest dość rzadki, warto się nad nim zastanowić. Załóżmy, że możemy dodać filtr, aby zawęzić zbiór zwracanych miast.

SELECT 
   c.CityID
  ,c.CityName
  ,c.StateProvinceID
FROM Cities AS c
WHERE c.CityName LIKE "Bos*"
  AND MyUCase([c].[CityName])="BOSTON";
Prześledzony ODBC SQL będzie wyglądał tak:

SQLExecDirect: 
SELECT 
   "CityName"
  ,"c"."CityID" 
FROM "Application"."Cities" "c" 
WHERE ("CityName" LIKE 'Bos%' ) 
Access może zdalnie LIKE z powrotem do źródła danych, co skutkuje odzyskaniem znacznie mniejszego zestawu danych. Nadal będzie przeprowadzać lokalną ocenę MyUCase() na wynikowym zbiorze danych. Zapytanie działa znacznie szybciej po prostu z powodu zwróconego mniejszego zestawu danych.

To mówi nam, że jeśli mamy do czynienia z niepożądanym scenariuszem, w którym nie możemy łatwo przekonwertować złożonej funkcji VBA z zapytania, nadal możemy złagodzić złe skutki, dodając filtry, które można zdalnie zmniejszyć, aby zmniejszyć początkowy zestaw rekordów, z którymi ma pracować program Access.

Uwaga na temat sargability

W poprzednich przykładach zastosowaliśmy funkcję skalarną na kolumnie. Może to potencjalnie sprawić, że zapytanie będzie „niepodlegające sargowaniu”, co oznacza, że ​​silnik bazy danych nie jest w stanie zoptymalizować zapytania przy użyciu indeksu do wyszukiwania i znajdowania dopasowań. Część „sarg” słowa „sargability” odnosi się do „argumentu wyszukiwania”. Załóżmy, że mamy indeks zdefiniowany w źródle danych w tabeli:

CREATE INDEX IX_Cities_CityName
ON Application.Cities (CityName);
Wyrażenia takie jak UCASE(CityName) uniemożliwia silnikowi bazy danych korzystanie z indeksu IX_Cities_CityName ponieważ silnik jest zmuszony do oceny każdego wiersza jeden po drugim, aby znaleźć dopasowanie, tak jak zrobił to Access z niestandardową funkcją VBA. Niektóre aparaty baz danych, takie jak najnowsze wersje programu SQL Server, obsługują tworzenie indeksów na podstawie wyrażenia. Gdybyśmy chcieli zoptymalizować zapytania za pomocą UCASE() Transact-SQL, możemy dostosować definicję indeksu:

CREATE INDEX IX_Cities_Boston_Uppercase
ON Application.Cities (CityName)
WHERE UCASE(CityName) = 'BOSTON';
Dzięki temu SQL Server może potraktować zapytanie za pomocą WHERE UCase(CityName) = 'BOSTON' jako zapytanie sargable, ponieważ może teraz używać indeksu IX_Cities_Boston_Uppercase aby zwrócić pasujące rekordy. Jeśli jednak zapytanie pasuje do 'CLEVELAND' zamiast 'BOSTON' , sargowalność zostaje utracona.

Niezależnie od tego, z jakim silnikiem bazy danych faktycznie pracujesz, zawsze lepiej jest projektować i używać zapytań sargable, gdziekolwiek jest to możliwe, aby uniknąć problemów z wydajnością. Kluczowe zapytania powinny mieć indeksy obejmujące, aby zapewnić najlepszą wydajność. Zachęcam do dokładniejszego zapoznania się z sargowalnością i pokrycia indeksów, aby uniknąć projektowania zapytań, które w rzeczywistości nie są sargowalne.

Wnioski

Sprawdziliśmy, jak program Access obsługuje stosowanie filtrów z programu Access SQL do zapytań ODBC. Zbadaliśmy również różne przypadki, w których program Access konwertuje różne typy odwołań na parametr, umożliwiając programowi Access przeprowadzenie oceny poza warstwą ODBC i przekazanie ich jako danych wejściowych do przygotowanej instrukcji ODBC. Przyjrzeliśmy się również, co się dzieje, gdy nie można go sparametryzować, zwykle z powodu zawierania odwołań do kolumn jako danych wejściowych. Może to mieć wpływ na wydajność podczas migracji na serwer SQL.

W przypadku niektórych funkcji program Access może być w stanie przekonwertować wyrażenie tak, aby zamiast tego używało funkcji skalarnych ODBC, co umożliwia programowi Access zdalne sterowanie wyrażeniem do źródła danych ODBC. Jedną z konsekwencji tego jest to, że jeśli implementacja funkcji skalarnej jest inna, może to spowodować, że zapytanie będzie zachowywać się inaczej lub może działać szybciej/wolniej. Widzieliśmy, w jaki sposób funkcja VBA, nawet prosta, która otacza zdalnie usuwalną funkcję skalarną, może zniweczyć próby oddalenia wyrażenia. Dowiadujemy się również, że jeśli mamy sytuację, w której nie możemy dokonać refaktoryzacji złożonej funkcji VBA z zapytania Access/recordsource/rowsource, możemy przynajmniej złagodzić kosztowne pobieranie, dodając dodatkowe filtry w zapytaniu, które można oddalić, aby zmniejszyć ilość zwróconych danych.

W następnym artykule przyjrzymy się, jak połączenia są obsługiwane przez program Access.

Szukasz pomocy dotyczącej programu Microsoft Access? Zadzwoń do naszych ekspertów już dziś pod numer 773-809-5456 lub napisz do nas na adres [email protected].


  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 wiosenne czyszczenie bazy danych

  2. Jak utworzyć pole obliczeniowe w programie Access

  3. Pułapki, których należy unikać podczas korzystania z nowej wersji Microsoft SSMA 7.8

  4. 25 skrótów Microsoft Access pozwalających zaoszczędzić czas w tabelach w widoku arkusza danych

  5. Jak mogę stwierdzić, czy baza danych jest wysokiej jakości?