SQL - problem z zapytaniem a może danymi w bazie

SQL - problem z zapytaniem a może danymi w bazie
WP
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 12 lat
  • Postów:10
0

Zacząłem się bawić SQL-em i od razu na początku mnie przygniotło :(

mam takie zapytanie ( a tak przy okazji czy jest ono poprawne pod względem "optymalizacji" ? )

Kopiuj
select DATEPART(wk, R_DATE), Count(R_ID) from Tabela1
WHERE R_DATE >= '130601'
  AND R_DATE <= '130605'
  AND T_MODE = '0'
  AND R_CANC = '0'
  AND USR_NO Like '2%'
  AND R_ID IN (SELECT R_ID FROM Tabela2
                     WHERE R_DATE >= '130601'
                       AND R_DATE <= '130605'
                       AND RET_NO = '0'
                       AND ORDER_NO <> '0'
                       AND ART_NO <> '12345678')
GROUP by DATEPART(wk, R_DATE)
ORDER by DATEPART(wk, R_DATE)

mamy 2 bardzo podobne do siebie tabele z elementami wspólnymi z taką różnicą że jedna zawiera
"nagłówki danych" (1) a druga już jakieś konkretne szczegóły (2) - czyli można by rzec: klasyczny układ
Baza jest oparta na MS SQL 2008 ( wersja express )

i teraz mam dziwną sytuację :
np. próbujemy zmienić kryteria ( zmieniamy tylko i wyłącznie R_DATE w obydwu członach zapytania )

czyli to samo ale dla dat :od '130602' do '130605'

Kopiuj
select DATEPART(wk, R_DATE), Count(R_ID) from RECEIPT
WHERE R_DATE >= '130602'
  AND R_DATE <= '130605'
  AND T_MODE = '0'
  AND R_CANC = '0'
  AND USR_NO Like '2%'
  AND R_ID IN (SELECT R_ID FROM ARTICLE
                     WHERE R_DATE >= '130602'
                       AND R_DATE <= '130605'
                       AND RET_NO = '0'
                       AND ORDER_NO <> '0'
                       AND ART_NO <> '12345678')
GROUP by DATEPART(wk, R_DATE)
ORDER by DATEPART(wk, R_DATE)

wszystko pięknie działa.... idziemy dalej

Kopiuj
R_DATE >= '130603'
R_DATE <= '130605'

wszystko pięknie działa....

ale już przy

Kopiuj
R_DATE >= '130604'
R_DATE <= '130605'

SQL staje okoniem ... i nic nie chce zwrócić... choćby i czekać kilka minut
myślę sobie , może ten dzień '130604' jest jakiś trefny , może jakiś krzak w bazie jest

ale jak zapytam

Kopiuj
R_DATE >= '130604'
R_DATE <= '130606'

no to juz mam wynik : ( oczywiście z uwzględnieniem tego dnia 130604 i 05 i 06 )

co ciekawe zakres

Kopiuj
R_DATE >= '130604'
R_DATE <= '130604'

też nam zwraca wynik

kombinowałem jeszcze z wieloma wariantami
nawet odległymi w czasie kilku miesięcy

Kopiuj
R_DATE >= '130101'
R_DATE <= '130604'

wszystko pięknie działa...

co może być przyczyną takiego zachowania , jak sprawdzić co blokuje mojego SQL, dlaczego nie może zwrócić wyniku
( może gdzieś jakieś sprytne logi gdzie to jest widać ... )
może jakiś niepoprawna konsystencja danych w bazie , ale jak to sprawdzić , jak wyszukać ... itd. ?

dziękuję za wszelkie podpowiedzi

Pozdrawiam
wporzak

edytowany 1x, ostatnio: wporzak
crowa
  • Rejestracja:ponad 18 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Poznań
  • Postów:295
0
Kopiuj
SELECT DATEPART(wk, R_DATE), COUNT(R_ID) FROM Tabela1 t1 inner join Tabela2 t2
on t1.R_ID = t2.R_ID
and t1.R_DATE >= '130601'
  AND t1.R_DATE <= '130605'
  AND t1.T_MODE = '0'
  AND t1.R_CANC = '0'
  AND t1.USR_NO LIKE '2%'
                     AND t2.R_DATE >= '130601'
                       AND t2.R_DATE <= '130605'
                       AND t2.RET_NO = '0'
                       AND t2.ORDER_NO <> '0'
                       AND t2.ART_NO <> '12345678'
GROUP BY DATEPART(wk, t1.R_DATE)
ORDER BY DATEPART(wk, t1.R_DATE)

tak na szybko. Wykonaj to zapytanie i sprawdz jaj wyglada aktualny plan zapytania


Tomasz Andrzejewski
Delphi (XE3-XE7) framework engineer @ InterLan
MCP: Microsoft SQL Server 2008, Implementation and Maintenance
WP
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 12 lat
  • Postów:10
0

dzięki za podpowiedź, ale niestety efekt jest dokładnie taki sam ... przy zakresie dat

Kopiuj
R_DATE >= '130604'
R_DATE <= '130605'

totalna zwiecha SQL-a,

dodatkowo , Twoja wersja zapytania zwraca troszkę zawyżone wyniki :
kolumna R_ID w tabeli 2 zawiera powtarzające się wartości
dlatego gdzieś tam trzeba jakiegoś DISTINCT-a wstawić

ale nie to jest chyba głównym problemem ...

wporzak

crowa
  • Rejestracja:ponad 18 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Poznań
  • Postów:295
0

masz jakies skrypty ktore utworza te tabele i zainsertuja dane?
Pokaz jak wyglada plan zapytania.


Tomasz Andrzejewski
Delphi (XE3-XE7) framework engineer @ InterLan
MCP: Microsoft SQL Server 2008, Implementation and Maintenance
Marcin.Miga
  • Rejestracja:prawie 17 lat
  • Ostatnio:dzień
  • Postów:2792
0

Załóż na nowo indeksy.

WP
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 12 lat
  • Postów:10
0

@ crowa

masz jakies skrypty ktore utworza te tabele i zainsertuja dane?
Pokaz jak wyglada plan zapytania.

żadnych skryptów ... , baza utworzona poprzez kreatora ,
przepraszam ale nie bardzo rozumiem , czym jest "plan zapytania"

@Marcin.Miga
Baza nie posiada indeksów ... czy to, że ich nie ma jest przyczyną takiego zachowania ?

jeszcze kilka, być może istotnych faktów :

baza jest może rzeczywiście i duża, ( składa się z 5 tabel - kilka kolumn, które zawierają odpowiedno )

13 mln
400 tys
1,9 mln
2,4 mln
1,7 mln rekordów

baza służy jako archiwum danych, co jakiś czas dane są uzupełniane poprzez DTS z tabel excelowych

co jakiś czas potrzebny jest jakiś prosty raport ,
i tak testujac natknąłem się na ten dziwny przypadek , przy czym wcześniej pisałem że SQL totalnie odmawia
posłuszeństwa przy wariancie

Kopiuj
R_DATE >= '130604'
R_DATE <= '130605'

ale postanowałem go przetrzymać , i... zwróćił dane ale po 8 minutach
dla przypomnienia warianty z sąsiednimu datami, trwają tylko 2-3 sekundy
jedynie ten wariant dat tak dziwnie się zachowuje...

żeby jeszcze było ciekawiej , to jest takich baz jest kilka,
( zawierają dokładnie te same dane ale pochodzą z różnych ośrodków )
, i tam nie występuje takie zjawisko , być może metodą przypadkowości napotkam się znów na taki przypadek.

=============================================
zatem jeszcze raz w skrócie : problem jest ( tylko na jednej bazie ) kiedy wybieram dane za okres

Kopiuj
R_DATE >= '130604'
R_DATE <= '130605'

problemu nie ma, kiedy wybieram inny dowolny okres

np.

Kopiuj
R_DATE >= '130603'
R_DATE <= '130605'

lub

Kopiuj
R_DATE >= '130604'
R_DATE <= '130604'

Pozdrawiam
wporzak

CI
Skoro to jest typ datowy to takie zachowanie ze strony servera jest normlane. Czego szukać pomiędzy dniem 04, a 05? 0.45555???? Bez jaj. Zadawajmy bazie pytania z głową, albo rób jakąś walidacje wcześniej. W pozostałych przypadkach problemu nie ma co też jest oczywiste.
ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 16 godzin
0

13M rekordów i nie masz żadnych indeksów? oO
Co to plan zapytania znajdziesz w 30s przez google. Poszukaj sobie razem z Management Studio, to dowiesz się, jak to włączyć i zobaczyć. Interesuje Cię taka nieco abstrakcyjna wielkość, jaką jest koszt zapytania, oraz, a może przede wszystkim, indeksy sugerowane przez Management Studio. Z mojego doświadczenia wynika, że koszt zapytania ostatniego, "końcowego" elementu wyższy od 0,1 to dużo w przypadku często wykonywanych zapytań. Indeksy znajdziesz na samej górze podglądu planu.
Na szybko znalazłem taki tutorialik: http://www.mssqltips.com/sqlservertip/1945/missing-index-feature-of-sql-server-2008-management-studio/. Jak dodasz najważniejsze indeksy, to zapytania zaczną się wykonywać szybciej nie pięciokrotnie, a o pięć, albo i sześć rzędów wielkości.


edytowany 1x, ostatnio: ŁF
WP
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 12 lat
  • Postów:10
0

OK, mogę zgłębić tajniki "zakładania indeksów" itd, itp
ale nurtuje mnie pytanie , jak to możliwe że zapytanie "dwudniowe" typu

Kopiuj
select xxx from tabela WHERE r_DATE >= '130604' AND r_DATE >= '130605'

potrzebuje 8 minut ( gdzie mamy do czynienia z powiedzmy z kilkoma tysiącami rekordów do całkowitego przeanalizowania )
a zapytanie kilkumiesięczne ( około 2 mln rekordów ) r_DATE >= '130104' AND r_DATE >= '130605' jest zwracane po 3 sekundach
Indeksy zgadza się , pewnie podwyższają wydajność, ale to chyba nie ten przypadek ... ? , odczyt z bazy jest raz na kilka dni ( żadnych update-ów )
ale jeśli to jest taki przypadek , że trafiliśmy tutaj na fragment danych , które mogą być tylko i wyłącznie szybko odczytane
jeśli jest zastosowany mechanizm indeksacji, to nie będę się upierał , zrobię tak aby działało dobrze, niezależnie od wybranej daty :-)

Pozdrawiam
wporzak

Marcin.Miga
Załóż indeksy, potem się zastanawiaj.
vpiotr
Indeksy nie podwyższają wydajność tylko ją DOSTARCZAJĄ. Bez indeksów nie można rozmawiać o wydajności, co najwyżej o niewydajności. W zapytaniu konkretnie w tym poście: a) zmień typ danych na polu r_date lub dodaj dodatkowe r_date_int (typu int). b) załóż na tym polu indeks. c) wróć jeśli nadal coś będzie nie tak.
ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 16 godzin
0

Bo np. masz pofragmentowaną tabelę, albo optymalizator głupieje. Porównaj plany obu zapytań, to się dowiesz.


WP
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 12 lat
  • Postów:10
0

Różnice w zapytaniach wyglądają następująco, szczegóły w załączniku - ( o ile o to chodziło )
niestety nie posiadam takiej wiedzy aby stwierdzić czy jest to OK, czy NOT OK ,
i co jest przyczyną takiego zachowania

a jak sprawdzić czy "optymalizator nie głupieje" ?

edytowany 1x, ostatnio: wporzak
ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 16 godzin
1

Patrząc na plan zapytania mogę stwierdzić jedno - brakuje mi wiedzy, żeby to wytłumaczyć.
Załóż brakujące indeksy i zobaczysz, że będzie dobrze.


WP
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 12 lat
  • Postów:10
0

No dobra, nie będę się upierał... :-)

ale , ponieważ jeszcze nie zgłębiłem zagadnienia zakładania indeksów,
to oczywiście przy tak postawionym stwierdzeniu

załóż brakujące indeksy
też zaczynam się gubić, jak zidentyfikować typ indeksu, znaczy się , który jest brakujący ( obowiązkowy )
a który można sobie darować itd

a może po prostu trzeba zastosować wskazówkę jaka jest wyświetlana podczas uruchamiania planu :( missing index details )

Kopiuj
The Query Processor estimates that implementing the following index could improve the query cost by 70.4406%.
USE [nazwaBazy]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[Tabela2] ([RET_ITEM],[R_DATE],[ART_NO],[ORDER_NO])
INCLUDE ([R_ID])
GO

czy może to trzeba zrobić jakoś inaczej ?
a czy można założyć indeksy w niewłaściwy sposób ?

ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 16 godzin
0
wporzak napisał(a):

a może po prostu trzeba zastosować wskazówkę jaka jest wyświetlana podczas uruchamiania planu :( missing index details )

Napisałem to kilka postów temu... Jeśli nie czytasz uważnie naszych odpowiedzi, to jaki jest sens odpowiadania?
Po założeniu indeksu uruchom ponownie zapytanie i zerknij na plan, bardzo prawdopodobne, że będziesz mieć kolejny indeks do założenia. Ale weź pod uwagę, że MS czasem się myli i sugeruje założenie indeksu, który już istnieje - bądź ostrzeżon. Ponadto im więcej indeksów, tym wolniej działają inserty i update'y, więc jeśli dołożenie kolejnego indeksu "przyspieszyło" zapytanie o dwa procenty, to możesz sobie taki indeks darować.


edytowany 1x, ostatnio: ŁF
WP
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 12 lat
  • Postów:10
0

założyłem indeksy ( "jakieś tam"- defaultowe ) bo jak zaczęłem czytać o rodzajach to się pogubułem , jeszcze jakieś klucze się tam przewijały .... :(
i rzeczywiście , problem już nie wystąpuje,

indeksy założyłem na 2 głównych kolumnach , teraz pewnie pojawią się wątpliwości na których
jeszcze powinienem... rozumiem że jak się znów pojawią jakieś problemy wydajnościowe to znów dodać kolejny indeks ?

który diagram , ( jaki wpis lub wartość ) ukazany planie świadczy że mamy właśnie taki problem

no.. jeszcze dużo muszę się nauczyć ! :-)

dzięki za pomoc

wporzak

edytowany 1x, ostatnio: wporzak
Marcin.Miga
  • Rejestracja:prawie 17 lat
  • Ostatnio:dzień
  • Postów:2792
0

To nie jest do końca tak, że zakładaasz sobie indeksy jekie chcesz...
Zresztą już to powyżej napisano. odam tylko od siebie, że na etapie projektowania powinno być zaznaczone najczęstsze wybieranie / sortowanie i a tych kolumnach zakładasz indeks(y). Czasem może się zdarzyć, że będziesz musiał założyć indeks wielokolumnowy. W MS SQL kiedyś był taki problem (nie wiem, czy teraz, bo już dość długo z nim nie pracuję), że jeśli w zapytaniu nie użyłeś wszyskich kolumn z indeksu, to domyślnie z niego nie korzystał (ale z tego co pamiętam, to można wymusić stosowanie danego indeksu). Można też zrobić sztuczkę taką:
załóżmy, że mamy indeks na pola "typ", "data" i chcemy wykazać wszystkie dokumenty (bez podziału na typ) z danego okresu. Standardowo zapisalibyśmy: WHERE data BETWEEN ... AND ... ale wtedy istnieje szansa, że nie wykorzystamy indeksu. Więc można zapytanie delikatnie zmodyfikować: WHERE typ=typ AND data BETWEEN ... AND ... co na to samo wychodzi, a indeks już był używany.
Ja osobiście wychodzę z założenia, że zapytania piszemy pod indeksy, nie odwrotnie. A te muszą powstać na etapie projektowania.

crowa
  • Rejestracja:ponad 18 lat
  • Ostatnio:około 8 lat
  • Lokalizacja:Poznań
  • Postów:295
0

A wiec (podobno nie zaczyna sie tak zdania).
Roznice w planie zapytania moga wynikac z ilosci danych zwracanych przez laczone dataesty.
Optymalizator odpowiednio dobiera wtedy sposoby zlaczen.

Zaloz indexy (poczytaj tez o indexach typu include). Jedna z technik jakie mozesz zastosowac jest przerzucenie glownego datasetu danych do tabeli tymczasowej i tak zawezony dataset obrabiasz dalej.


Tomasz Andrzejewski
Delphi (XE3-XE7) framework engineer @ InterLan
MCP: Microsoft SQL Server 2008, Implementation and Maintenance
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)