2012-01-27 30 views
5

Mam problem ze stosunkowo prostym zapytaniem i planem wykonania Access wybierz dla niego.Jak mogę ustawić MS-Access wybrać inny/właściwy plan wykonania dla mojego zapytania

Zapytanie jest tej postaci

SELECT somethings 
FROM A INNER JOIN (B INNER JOIN (C INNER JOIN D ON ...) ON ...) ON ... 
WHERE A.primaryKey= 1 AND D.d = 2; 

C i D mają względnie kilka rzędów. A i B mają kilka tysięcy rzędów.

Zapytanie, które zwraca 2 wiersze (nie ma pewności, czy jest to istotne) jest naprawdę wolne. Działa w ciągu 17 sekund. Jeśli usunę część AND D.d = 2 klauzuli where, zapytanie zwróci teraz 4 wiersze i zostanie uruchomione natychmiast.

Tak więc rozumiem, że silnik JET może natychmiast uruchomić zapytanie bez filtra w D.d, a następnie natychmiast wykonać filtr (tylko 4 wiersze do przefiltrowania). Dlatego nie powinno być zbyt długo, aby uruchomić zapytanie z filtrem D.d = 2.

Próbowałem utworzyć kwerendę bez filtru i zawrzeć ją w innym zapytaniu, które odfiltrowałoby wynik, ale wciąż jest wolne. Domyślam się, że silnik JET jest wystarczająco inteligentny, aby "spłaszczyć" pod-zapytania, aby wynik był taki sam.

Ponieważ nie mogłem wykonać zapytania, tak jak chciałem, skorzystałem z funkcji JETSHOWPLAN, aby program Access wygenerował plan wykonania. Oto, co znalazłem:

Dla szybkiego zapytania (bez pytania D.d = 2) pierwszym krokiem planu kwerend jest zastosowanie filtru A.primaryKey = 1 w tabeli A. Rezultatem jest zbiór danych z 1 rzędu z ponad 30000. Wtedy połączenia wydają się być wykonywane od A do D przy użyciu indeksu z zestawem danych, który nigdy nie przekracza 4 wierszy.

Powolne zapytanie wydaje się być wykonane w kolejności odwrotnej. D i C są połączone najpierw, a następnie testowane jest D.d = 2. Następnie wykonywane są sprzężenia od C do A. W ten sposób dane, które muszą być łączone z D na C, z C na B iz B na A są znacznie większe. Po wykonaniu wszystkich powiązań i przed wykonaniem A.primaryKey=1 zestaw danych będzie miał 120 000 wierszy.

Czy istnieje sposób wymuszenia odpowiedniego planu zapytania w programie Access?

Mam nadzieję, że było jasne. Daj mi znać, jeśli chcę opublikować plany zapytań. Nie zrobiłem tego, ponieważ są dość duże.

Dzięki z góry,

MP

+2

Ponieważ nie można dostarczyć wskazówek do planowania zapytań, ja podejrzewasz, że jesteś SOL. Jeśli jest to krytyczne z punktu widzenia wydajności, możesz dołączyć szybką część zapytania do tabeli scratch i użyć jej dla innego zapytania "D.d = 2". Wiem, że brzmi to paskudnie (jest!), Ale nie wiem, co jeszcze mógłbyś zrobić, oprócz życia z powolnością pojedynczego zapytania, które masz teraz. – HansUp

+0

@HansUp: Dzięki za twój wkład. Obawiałem się, że będę musiał użyć tak brzydkiego hacka, ale jeśli nie znajdę innego rozwiązania, będę musiał użyć jednego. Moi użytkownicy czekają na wynik tego zapytania kilka razy dziennie, a 17 sekund to długi czas, kiedy wszystko co robisz, to gapienie się na ekran. –

Odpowiedz

2

W końcu udało mi się to osiągnąć, miksując rzeczy do momentu uzgodnienia z planerem zapytań. I wyizolowanego ze „A.primaryKey = 1” w sub-zapytania do zapewnienia to wykonywane przed A dołączył do B. Jest to coś takiego:

SELECT ... 
FROM (SELECT ... FROM A WHERE a.primaryKey=1) AS qryA 
    INNER JOIN B ... 
WHERE D.d = 2; 
2

zrobić to w kodzie VBA? Chodzi o to, aby wyjąć część, która jest wolna i wykonać zapytanie, które szybko zwraca, a następnie dodać powolną część w sql.

db.execute "select * from qryFast inner join d on qryfast.dkey = d.d where d.d = 2 

Nie kod VBA w module różni się od pod-zapytania. @HansUp wyjaśnił nam, że wykonanie kodu w jednym kroku, jak pokazałem powyżej, nie poprawi wydajności. Powinieneś być w stanie szybko uzyskać wyniki w pamięci, jeśli wiesz, jak pisać kod w modułach, ale wtedy wyjście tam, gdzie potrzebujesz, może zwolnić.


innymi słowy, powinieneś być w stanie uzyskać wyniki qryFast do rekordów w pamięci szybko, a następnie zastosować filtr na qryFast.dkey = d, a także szybko uzyskać zestaw rekordów z "wybierz * z tableD, gdzie d = 2", aby wyszukać powiązane informacje, które chcesz z tableD, ale usunąć wszystkie te rzeczy z pamięci i do miejsca, gdzie twój front-end może dostęp to może potrwać dłużej niż 17 sekund, które czekają teraz.


W rzeczywistości, to może kopnąć go w tyle spodni jeśli zmienisz qryFast obejmuje stan, w którym DKEY = 2 (lub niezależnie od PK na zgłoszoną)


inny pomysł: czy 3 zapytania, qryFast, qryD i qryFastWithD łączące te dwa. Po prostu wyrzucam pomysły tutaj.


lub, jak mówią w swoich komentarzach, spróbuj zawierające różne części kwerendy w pod-zapytań, ale myślę, że optymalizator nie daj się nabrać na taki trick, jeżeli przeniesienie to kawałek w pod-zapytanie nie działa. Za wszelką cenę, cokolwiek działa, weź to.

+0

Nie, nie próbowałem, tylko zgadywanie, że optymalizator może nie rozszerzyć się na VBA. Zamiast robić to wszystko w jednym poleceniu SQL, jak pokazałem, mógł spróbować podzielić je na wiele kroków w VBA. – Beth

+0

Chyba że coś przegapię, to jest to samo, co już próbowałem. Utworzono podkwerendę i użyłem tego jako źródła innego zapytania, które po prostu WYBIERZ * Z qryFast WHERE d = 2. –

+1

@Beth: Wszystkie zapytania SQL, niezależnie od tego, czy pochodzą z przechowywanego zapytania, czy są generowane w VBA, są nadal wykonywane przez JET silnik ... myślę. Dobrze... ? –