ďťż
 
=?iso-8859-2?Q?=5BMS_SQL=5D_Czy_mo=BFna_wywo=B3a=E6_funkcje_t ylko_raz_dla?==?iso-8859-2?Q?_ca=B3ego_zbioru_=BCr=F3d=B3owego=3F?= ďťż
 
=?iso-8859-2?Q?=5BMS_SQL=5D_Czy_mo=BFna_wywo=B3a=E6_funkcje_t ylko_raz_dla?==?iso-8859-2?Q?_ca=B3ego_zbioru_=BCr=F3d=B3owego=3F?=
Zobacz wiadomości
 
Cytat
A gdyby tak się wedrzeć na umysłów górę, / Gdyby stanąć na ludzkich myśli piramidzie, / I przebić czołem przesądów chmurę, / I być najwyższą myślą wcieloną. . . Juliusz Słowacki, Kordian
Indeks BCB i MySQL subiekt gt fototapeta
 
  Witamy

=?iso-8859-2?Q?=5BMS_SQL=5D_Czy_mo=BFna_wywo=B3a=E6_funkcje_t ylko_raz_dla?==?iso-8859-2?Q?_ca=B3ego_zbioru_=BCr=F3d=B3owego=3F?=



Grzegorz Danowski - 22-06-2006 00:31
=?iso-8859-2?Q?=5BMS_SQL=5D_Czy_mo=BFna_wywo=B3a=E6_funkcje_t ylko_raz_dla?==?iso-8859-2?Q?_ca=B3ego_zbioru_=BCr=F3d=B3owego=3F?=
  Witam!

Mam wiele różnych zapytań odwołujących się do tabeli z fakturami. Są one
bardzo do siebie podobne, więc postanowiłem zrobić bazowe "sparametryzowane"
widoki, które będą podstawą do prostszych zapytań.

W tym celu stworzyłem tabelę z kryteriami:

Create Table Criteria(
CriteriaName Varchar(50) Not Null,
UserName Varchar(50) Not Null,
CriteriaValue Varchar(100) Not Null,
Constraint UK_Criteria Unique
(UserName, CriteriaValue)
)
Go

Dwa przykładowe kryteria:

Insert Into Criteria(UserName, CriteriaName, CriteriaValue)
Values('dbo', 'DateFrom', '20050101')
Go

Insert Into Criteria(UserName, CriteriaName, CriteriaValue)
Values('dbo', 'DateTo', '20051231')
Go

A następnie funkcję zwracającą wartość wybranego kryterium:

Create Function GetCriteriaByName(
@CriteriaName Varchar(50))
Returns Varchar(100)
As
Begin
Declare @CriteriaValue Varchar(100)
Select @CriteriaValue = CriteriaValue
From
Criteria
Where
UserName = User --kryteria bieżącego usera
And
CriteriaName = @CriteriaName
Return @CriteriaValue
End
Go

Mając tę funkcję zrobiłem "sparametryzowany" widok:

Create View SelectedInvoices
As
Select *
From
Invoices
Where
InvoiceDate Between
dbo.GetCriteriaByName('DateFrom')
And
dbo.GetCriteriaByName('DateTo')
Go

Wszystko działa, ale... strasznie wolno.
Proste zapytanie oparte na powyższym widoku (Select Top 1 * From
SelectedInvoices) wykonuje się ponad 20 sekund.
Oczywiście pole InvoiceDate jest zaindeksowane, poza tym w tabeli jest też
PK.

Dla porównania analogiczne zapytanie oparte na widoku z parametrami
wstawionymi na sztywno:

Create View SelectedInvoicesOld
As
Select *
From
Invoices
Where
InvoiceDate Between
'20050101' And '20051231'

wykonuje się w ułamku sekundy.

Najwyraźniej SQL Server wykonuje moją funkcję (GetCriteriaByName) dla
każdego rekordu, mimo, że parametrem tej funkcji jest ta sama wartość. Czy
da się zmienić ten stan rzeczy?
Widzę, że jest coś takiego jak właściwość funkcji "IsDeterministic", może to
jest jakiś trop?

A może zamiast kombinować ze "sparametryzowanymi" widokami, powinienem
zrobić funkcje ściągające odpowiednie dane, czyli np.:

Create Function SelectedInvoicesF(
@DateFrom DateTime, @DateTo DateTime)
Returns Table
As
Return
(
Select *
From
Invoices
Where
InvoiceDate Between @DateFrom And @DateTo
)

Proste zapytania korzystające z takiej funkcji wykonują się szybko. Ale czy
w przypadku dużej liczby rekordów wybranych przez funkcje oraz
skomplikowanych złączeń na zbiorze wynikowym SQL Server skorzysta z indeksów
założonych w tabeli Invoices? Miałem wrażenie, że w 2000 był z tym problem,
ale może się myle, albo też coś się zmieniło w 2005?

Pozdrawiam
Grzegorz





Marcin A. Guzowski - 24-06-2006 01:05

  Grzegorz Danowski napisał(a):
> Witam!
>
> Mam wiele różnych zapytań odwołujących się do tabeli z fakturami. Są one
> bardzo do siebie podobne, więc postanowiłem zrobić bazowe
> "sparametryzowane" widoki, które będą podstawą do prostszych zapytań.
> (..)

Generalnie źle rozwiązałeś całą sprawę stosując funkcje w taki sposób.
Deterministyczność funkcji użytkownika nie może być narzucona, aby funkcja
została przez optimizera za takową uznana, musi spełnić cały szerego warunków,
których w opisanym przypadku nie spełnisz (choćby dlatego, że masz w ciele
funkcji odwołanie do tabeli). SQL Server wywołuje więc funkcję per wiersz,
a biorąc pod uwagę jeszcze kilka kwiatków optymalizacyjnych zw. z funkcjami -
działa jak działa.

Proponuję przebudowanie koncepcji:
Cel - uproszenie zapytań końcowych.

Wariant 1

Tworzysz więc tabelę z kryteriami (dbo.Criteria), a następnie - widoki.
Etap z funkcjami jest niepotrzebny. Gdzie możesz - użyjesz joinów z tabelą kryteriów,
gdzie nie możesz - użyjesz podzapytań do tabeli z kryteriami. Wtedy całość będzie
zoptymalizowana - włącznie z podzapytaniami, (czyli m.in. podzapytanie wykona się raz,
a nie jak funkcja - per wiersz).

CREATE VIEW dbo.SelectedInvoices
AS
SELECT * FROM dbo.Invoices
WHERE
InvoiceDate BETWEEN
(SELECT CriteriaValue FROM dbo.Criteria WHERE CriteriaName = 'DateFrom' AND UserName = ...)
AND
(SELECT CriteriaValue FROM dbo.Criteria WHERE CriteriaName = 'DateTo' AND UserName = ...)

(dla pewności możesz dodać TOP 1 w podzapytaniach)

Wariant 2

Procedury. Zamiast widoków i warunków w WERE - procedury z tymi parametrami w wywołaniu.
Wtedy nie masz problemu z pobieraniem z dbo.Criteria, w ciele możesz definiować sobie
różne zmienne itd. Plany wykonań procedur też są trzymane, więc jeśli nie będzie następować
ich ciągła rekompilacja i zoptymalizujesz zapytania - będzie śmigać.

--
Pozdrawiam,
Marcin Guzowski
http://guzowski.info




Grzegorz Danowski - 27-06-2006 00:08
=?iso-8859-2?Q?Re:_=5BMS_SQL=5D_Czy_mo=BFna_wywo=B3a=E6_funkc je_tylko_raz?==?iso-8859-2?Q?_dla_ca=B3ego_zbioru_=BCr=F3d=B3owego=3F?=
  Użytkownik "Marcin A. Guzowski" <tu_wstaw_moje_imie@guzowski.info> napisał w
wiadomości news:e7hstn$4vp$1@atlantis.news.tpi.pl...
>> postanowiłem zrobić bazowe "sparametryzowane" widoki, które będą podstawą
>> do prostszych zapytań.
(...)
> Proponuję przebudowanie koncepcji:
> Cel - uproszenie zapytań końcowych.
>
> Wariant 1
>
> Tworzysz więc tabelę z kryteriami (dbo.Criteria), a następnie - widoki.
> Etap z funkcjami jest niepotrzebny. Gdzie możesz - użyjesz joinów z tabelą
> kryteriów,
> gdzie nie możesz - użyjesz podzapytań do tabeli z kryteriami. Wtedy całość
> będzie
> zoptymalizowana - włącznie z podzapytaniami, (czyli m.in. podzapytanie
> wykona się raz,
> a nie jak funkcja - per wiersz).
>
> CREATE VIEW dbo.SelectedInvoices
> AS
> SELECT * FROM dbo.Invoices
> WHERE
> InvoiceDate BETWEEN
> (SELECT CriteriaValue FROM dbo.Criteria WHERE CriteriaName = 'DateFrom'
> AND UserName = ...)
> AND
> (SELECT CriteriaValue FROM dbo.Criteria WHERE CriteriaName = 'DateTo'
> AND UserName = ...)

Przed wysłaniem na grupę swego pierwszego postu testowałem i takie
rozwiązanie (niemal identyczne) i było ono kilkakrotnie wolniejsze (1,5 s.)
w stosunku do sztywnego wpisania parametrów do zapytania (0,1 s.).

> (dla pewności możesz dodać TOP 1 w podzapytaniach)

Dodanie Top 1 dodało skrzydeł zapytaniu - teraz jest już niewiele wolniejsze
(0,2 s.) od zapytania ze sztywnymi parametrami. Dzięki.

> Wariant 2
>
> Procedury. Zamiast widoków i warunków w WERE - procedury z tymi
> parametrami w wywołaniu.
> Wtedy nie masz problemu z pobieraniem z dbo.Criteria, w ciele możesz
> definiować sobie
> różne zmienne itd. Plany wykonań procedur też są trzymane, więc jeśli nie
> będzie następować
> ich ciągła rekompilacja i zoptymalizujesz zapytania - będzie śmigać.

Z procedurami jest ten problem, że zapytania są dość złożone a równocześnie
jest wiele bardzo podobnych zapytań do siebie, np. filtrowanie faktur tylko
z określonego okresu, tylko określonej grupy towarowej i wybranego klienta.
Stąd "sparametryzowane" widoki były pomysłem na uniknięcie dublowania kodu.

Pozdrawiam
Grzegorz
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • effulla.pev.pl
  • comp
    [oracle] - Oracle SQL Developer - co to jest SID? MS Sql Server 2000 i Server 2003 [MS SQL + kontakty outlook]CZy kontakty moge być zewnętrzne? [oracle] Baza danych do kursy Introduction to Oracle9i:PL/SQL ? Skąd ją pobrać ? ms sql 2000 i ms server 2003 problem z logowaniem [MS SQL 2000] - wielkosc strony danych a wielkosc klastra dyskowego [ms sql] Przeniesienie bazy z wszystkimi dodatkami (dts, jobs, replikacja) na inny server ? konkurs SQL Injection - 10 PLN na GSM dla pierwszej osoby, ktora dostanie sie do bazy Re: Gdzie mozna jeszcze kupic Microsoft SQL 2000 Enterprise Edition?? [ps] eksport setow z automatu
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • atanvarne633.opx.pl
  • Cytat

    Decede mihi sole - nie zasłaniaj mi słonca.
    Gdy kogoś kochasz, jesteś jak stworzyciel świata - na cokolwiek spojrzysz, nabiera to kształtu, wypełnia się barwą, światłem. Powietrze przytula się do ciebie, choćby był mróz, a ty masz w sobie tyle radości, że musisz ją rozdawać wokoło, bo się w tobie nie mieści
    Hoc fac - tak czyń.
    A tergo - od tyłu; z tyłu.
    I czarne włosy posiwieją. Safona

    Valid HTML 4.01 Transitional

    Free website template provided by freeweblooks.com