2013-10-17 22 views
5

Piszę funkcję w ColdFusion, która zwraca pierwszą parę rekordów, które pasują do danych wprowadzonych przez użytkownika, a także całkowitą liczbę pasujących rekordów w całej bazie danych. Ta funkcja zostanie wykorzystana do podania autouzupełniania, więc szybkość/efektywność są jej najważniejszymi problemami. Na przykład, jeśli funkcja otrzymuje dane wejściowe "bl", to może powrócić {sampleMatches:["blue", "blade", "blunt"], totalMatches:5000}skutecznie odnajduję podzbiór rekordów oraz liczbę całkowitą

próbowałem to zrobić w jednym zapytaniu do celów prędkości, a zakończył się z czymś, co wyglądało tak:

select record, count(*) over() 
from table 
where criteria like :criteria 
and rownum <= :desiredCount 

Problem z tym rozwiązaniem jest to, że count(*) over() zawsze zwraca wartość :desiredCount. Widziałem podobne pytanie do mojego here, ale moja aplikacja nie ma uprawnień do utworzenia tabeli tymczasowej. Czy istnieje sposób na rozwiązanie mojego problemu w jednym zapytaniu? Czy istnieje lepszy sposób na rozwiązanie tego problemu? Dzięki!

+0

"Twoje kryteria" będą ograniczone do zestawu kryteriów, o których wiesz, że możesz używać indeksu? Jeśli użytkownik może ustawić dowolne szalone kryteria, wykona wiele pełnych skanów. – tbone

+0

Z ciekawości, czy funkcja ma być używana do autouzupełniania, jaki jest cel liczenia? –

+0

@tbone kolumna kryteriów jest już zindeksowana – Josh

Odpowiedz

5

Piszę to na mojej głowie, więc powinno się mieć do tego czasu, ale wierzę, że za pomocą następujących CTE

  • wymaga tylko napisać warunki raz
  • zwraca tylko ilość rekordów określić
  • ma poprawną całkowitą liczbę dodaną do każdego rekordu
  • i oceniana jest tylko raz

komunikat SQL

WITH q AS (
    SELECT record 
    FROM table 
    WHERE criteria like :criteria 
) 
SELECT q1.*, q2.* 
FROM q q1 
     CROSS JOIN (
     SELECT COUNT(*) FROM q 
     ) q2 
WHERE rownum <= :desiredCount 
+1

To się udało, dzięki! Aby to działało, musiałem usunąć słowa kluczowe "as", ale w przeciwnym razie działało gładko. – Josh

+0

@Ben - usunąłeś słowo kluczowe 'as', ponieważ nie jest ono obsługiwane przez Oracle, tx, ale usunięcie aliasses nie może być prawidłowe ?! * (Nie mogę tego teraz przetestować) * –

+0

Nie, przykro mi, że byłem głupi. Potrzebujesz aliasów. – Ben

3

Zagnieżdżona Podzapytanie powinien zwrócić wyniki chcesz

select record, cnt 
    from (select record, count(*) over() cnt 
      from table 
     where criteria like :criteria) 
where rownum <= :desiredCount 

Będzie to jednak zmusić Oracle całkowicie przetworzyć zapytania, aby wygenerować dokładny count. Wydaje się to mało prawdopodobne, jeśli chcesz wykonać autouzupełnianie, szczególnie gdy Oracle może zdecydować, że bardziej wydajne byłoby wykonanie skanowania tabeli pod numerem table, jeśli :criteria jest tylko b, ponieważ predykat ten nie jest wystarczająco selektywny. Czy na pewno potrzebujesz dokładnej liczby wyników? Czy jesteś pewien, że twój stolik jest wystarczająco mały/twój system jest wystarczająco szybki/twoje predykaty są wystarczająco selektywne, aby było to wymaganie, które możesz realistycznie spełnić? Czy byłoby możliwe zwrócenie mniej kosztownej (ale mniej dokładnej) oceny liczby rzędów? A może ograniczyć numer count do czegoś mniejszego (powiedzmy 100) i mieć wyświetlanie interfejsu użytkownika w stylu "i ponad 100 wyników"?

+0

+1 dla sugestii szacunkowej "100+ .." – Leigh

+0

W tym konkretnym przypadku potrzebuję dokładnej liczby. Ale w odniesieniu do przyszłych potrzeb, jak mogę zbudować oszacowanie? – Josh

+2

@Josh - To zależy. Można na przykład wygenerować plan zapytania i użyć szacowanej liczby zwróconych wierszy. Możesz użyć klauzuli "PRÓBKA" i pomnożyć przez odpowiedni współczynnik. Można tworzyć histogramy, które są oparte na częstości występowania danych i odświeżać je okresowo (lub nawet potencjalnie używać histogramów wygenerowanych przez optymalizator). –

Powiązane problemy