Natknąłem się na scenariusz, w którym muszę zwrócić złożony zestaw obliczonych wartości w punkcie przecięcia od „starszego” do obecnego.

Krótko mówiąc mam coś takiego...

with someofit as
(
   select id, col1, col2, col3 from table1
)

select someofit.*, 
  case when id < @lastLegacyId then
    (select ... from table2 where something = id) as 'bla'
   ,(select ... from table2 where something = id) as 'foo'
   ,(select ... from table2 where something = id) as 'bar'
  else
    (select ... from table3 where something = id) as 'bla'
   ,(select ... from table3 where something = id) as 'foo'
   ,(select ... from table3 where something = id) as 'bar'
  end
from someofit

Nie, tutaj leży problem ... Nie chcę ciągle sprawdzać tej sprawy dla każdego podwyboru, ale w tym samym czasie, gdy ten warunek ma zastosowanie, potrzebuję wszystkich wyborów w odpowiednim bloku spraw.

Czy jest mądrzejszy sposób, aby to zrobić?

Gdybym był w odpowiednim języku OO użyłbym czegoś takiego...

var common = GetCommonSuff()

foreach (object item in common)
{
   if(item.id <= lastLegacyId)
   {
      AppendLegacyValuesTo(item);
   }
   else
   {
      AppendCurrentValuesTo(item);
   }
}

Początkowo próbowałem wykonać 2 pełne selekcje ze złączem, ale to nie działa zbyt dobrze ze względu na wydajność / liczbę wierszy do oceny.

Wybory podrzędne szukają łącznej liczby wierszy, w których spełniony jest jakiś warunek inny niż dopasowanie id w tabeli 2 lub 3, ale te tabele mogą zawierać miliony wierszy.

Cte jest używany z 2 powodów ...

Najpierw pobiera tylko wiersze z tabeli 1, która mnie interesuje, więc od razu wykonuję tylko ułamek podselekcji w każdym przypadku.

Po drugie zwraca typowe rzeczy w pojedynczym wyszukiwaniu w tabeli 1

Jakieś pomysły?

EDYCJA 1:

Jakiś kontekst sytuacji...

Mam tabelę o nazwie „importy” (tabela 1 powyżej), która reprezentuje zadanie importu, w którym pobieramy dane z pliku (csv lub podobnego) i pobieramy rekordy do bazy danych.

Następnie mam tabelę o nazwie „kroki”, która reprezentuje reguły przetwarzania / czyszczenia, przez które przechodzimy, a każdy rekord zawiera nazwę sproc i kilka innych rzeczy dotyczących reguły.

Istnieje wtedy tabela sprzężenia, która reprezentuje regułę dla konkretnego importu „ImportSteps” (tabela 2 powyżej - dla danych bieżących), zawiera kolumnę „rowsaffected” i identyfikator importu

Więc dla obecnych prac mój sql jest dość prosty ...

Wybierz 123 456 z importów dołącz do importsteps

W przypadku starszych starszych rzeczy muszę jednak przejrzeć tabelę 3 ... tabela 3 jest tabelą przechowującą, zawiera każdy rekord kiedykolwiek zaimportowany, każdy wiersz ma identyfikator importu, a każdy wiersz zawiera wartości kluczy.

W nowych wierszach danych w tabeli 2 dla identyfikatora importu x, gdzie identyfikator kroku to y, zwróci moją wartość.

Na starszych danych muszę policzyć wiersze w gospodarstwie, gdzie col z = coś

Potrzebuję danych na temat około 20 importów, a dane te są powiązane z „siatką danych” w mojej aplikacji internetowej mvc (jeśli to ma jakiekolwiek znaczenie)

Cte, którego używam, określa za pomocą niektórych parametrów „bieżące 20 osób, które mnie interesują” te parametry reprezentują rekord początkowy i końcowy (uporządkowane według identyfikatora importu).

Moim największym problemem jest to, że trzymanie tabeli ... jest ogromne ... wiadomo, że pojedyncze zadania zawierają 500 000 + rekordów samodzielnie, a ta tabela zawiera wiele importowanych wierszy, więc potrzebuję, aby moje wyszukiwania w tej tabeli były tak szybkie, jak to możliwe i jak najmniej.

EDYCJA 2:

Rzeczywiste rozwiązanie (tylko kod zamszowy) ...

-- declare and populate the subset to reduce reads on the big holding table
declare table @holding ( ... )
insert into @holding
select .. from holding

select 
   ... common stuff from inner select in "from" below
   ... bunch of ...
   case when id < @legacy then (select getNewValue(id, stepid))
   else (select x from @holding where id = ID and ... ) end as 'bla'
from

(
   select ROW_NUMBER() over (order by importid desc) as 'RowNum'
   , ...
) as I
-- this bit handles the paging
where RowNum >= @StartIndex
and   RowNum < @EndIndex 

Nadal jestem pewien, że mogę to uporządkować, ale moje pierwotne zapytanie, które wyglądało jak rozwiązanie dotyczące rachunków, miało około 45 sekund czasu wykonania, to jest około 7

0
War 28 wrzesień 2012, 12:59

2 odpowiedzi

Najlepsza odpowiedź

Rozumiem, że podzapytania muszą zwracać pojedynczą wartość skalarną, prawda? Ten punkt jest ważny, ponieważ zapewnia, że ​​LEFT JOIN nie pomnoży wyniku.

;with someofit as
(
   select id, col1, col2, col3 from table1
)

select someofit.*, 
  bla = coalesce(t2.col1, t3.col1),
  foo = coalesce(t2.col2, t3.col2),
  bar = coalesce(t2.bar, t3.bar)
from someofit
left join table2 t2 on t2.something=someofit.id and somefit.id < @lastLegacyId
left join table3 t3 on t3.something=someofit.id and somefit.id >= @lastLegacyId 

Uważaj, że użyłem id >= @lastLegacyId jako uzupełnienia warunku, zakładając, że id nie jest nullable. Jeśli tak, potrzebujesz tam IsNull, tj. somefit.id >= isnull(@lastLegacyId,somefit.id).


Twoja edycja pytania nie zmienia faktu, że jest to prawie dosłowne tłumaczenie składni O-O.

foreach (object item in common)  --> "from someofit"
{
   if(item.id <= lastLegacyId)      --> the precondition to the t2 join
   {
      AppendLegacyValuesTo(item);   --> putting t2.x as first argument of coalesce
   }
   else                              --> sql would normally join to both tables
                                     --> hence we need an explicit complement
                                     --> condition as an "else" clause
   {
      AppendCurrentValuesTo(item);    --> putting t3.x as 2nd argument
                                      --> tbh, the order doesn't matter since t2/t3
                                      --> are mutually exclusive
   }
}

function AppendCurrentValuesTo     --> the correlation between t2/t3 to someofit.id

Teraz, jeśli rzeczywiście tego spróbowałeś i to nie rozwiąże twojego problemu, chciałbym wiedzieć, gdzie to się zepsuło.

3
RichardTheKiwi 28 wrzesień 2012, 14:00

Zakładając, że wiesz, że nie ma sprzecznych identyfikatorów między dwiema tabelami, możesz zrobić coś takiego (składnia DB2, bo to wiem, ale powinno być podobnie):

with combined_tables as (
    select ... as id, ... as bla, ...as bar, ... as foo from table 2
    union all
    select ... as id, ... as bla, ...as bar, ... as foo from table 3
)
select someofit.*, combined_ids.bla, combined_ids.foo, combined_ids.bar
    from someofit
    join combined_tables on someofit.id = combined_tables.id

Jeśli masz takie przypadki, jak nakładające się identyfikatory, możesz sobie z tym poradzić w sekcji Combined_tables()

1
dan1111 28 wrzesień 2012, 13:05