Pierwszy SELECT wykonuje się bardzo długo, kolejne "w normie"

0

Witam.

Mam następujący problem:
Po stworzeniu i uzupełnieniu bazy odpowiednimi danymi, pierwszy wykonywany SELECT wykonuje się bardzo długo (parędziesiąt sekund), czas wykonywania kolejnego (identycznego) jest już "w normie" (2-3 sekundy).
Pierwsza moja myśl to taka że chodzi o zapisywanie bazy w pamięci, ale nawet po restarcie aplikacji zapytania wykonują się w normalnym czasie.

Spotkaliście się z czymś takim?
Z czym to może być związane i jak sobie z tym poradzić ?

Z góry dziękuję.

0

Nie wiem jak firebird ale oracle posiada mechanizm cache'owania zapytań oraz mechanizm statystyk (jeśli nie używa się hintów). Oznacza to w praktyce mniej więcej tyle, że pierwsze zapytanie ładuje się do pamięci bazy danych i przy kolejnym wywołaniu (nawet z innymi parametrami) dostęp do wyniku jest znacznie szybszy niż w przypadku pierwotnego zapytania.

0

Przeczytaj to http://firebirdsql.org/manual/fbcache.html

Firebird tworzy cache dla wyników zapytań oraz statystyki, które później są zaciągane przy starcie. Każde kolejne zapytanie aktualizuje statystyki zatem nawet po restarcie apki masz gotowy cache na podstawie zapytań z poprzedniego uruchomienia.

0

@Koziołek dziękuję serdecznie za link.

A czy da się jakoś utworzyć taki cache dla konkretnego zapytania ?
Próbowałem najprościej:

FbCommand fbc = new FbCommand("SELECT [...], FbConnection);
FbDataReader fbdr = fbc.ExecuteReader();
fbdr.Read();

ale nie zdaje do egzaminu (kolejne "właściwe" otwarcie tabeli na podstawie tego zapytania trwa bardzo długo).

0

A tego to ci ja niestety nie powiem, ale zapewne jest w jakiś manualach. Jak chcesz mieć cache dla konkretnego zapytania, to spróbuj użyć https://www.ibphoenix.com/resources/documents/general/doc_1 (w google pytamy o materialized views), ale doczytaj dokładnie jak wygląda strategia aktualizacji tego typu danych. Zaleta jest to, że po pierwszym zapytaniu rzezasz po całej tabeli prostym select *.

0

@hipekk to jeszcze raz nawiązując do Oracle to cache'owanie zapytania możliwe jest tylko gdy używa się parametrów nawet wywołanie tego samego zapytania w taki sposób:

select * from tablica where id = x

spowoduje, że nie będzie cache. Natomiast wywołanie tego tak:

select * from tablica where id = :parametr

spowoduje, że wynik będzie szybszy. Możliwe ze FB ma podobnie

0
woolfik napisał(a):

Możliwe ze FB ma podobnie
Ale to już zależy od użytej biblioteki. Takie coś jak piszesz zadziała jeśli jawnie wyda się polecenie "Prepare" przed otwarciem DataSeta, czy innego komponentu. Wtedy przed jego zniszczeniem trzeba ręcznie zrobić "Unprepare". Nie wiem w czym pisze pytający, ale większość bibliotek do Firebirda przed wywołaniem zapytania robi Prepare, przed zamknięciem Unprepare. Zatem jeśli chcemy używać zapytań z parametrami należy raz zrobić Prepare(), na koniec dać Unprepare().

Ja bym odpalił problemowe zapytanie nie z poziomu programu, ale z poziomu np. IBExperta gdzie wtedy widać statystyki (ilość odczytów z poszczególnych tabel, czas przygotowania itp). I zobaczył jak to się na przy 1 razie oraz kolejnych.

0

Zapytania wykonywałem w EMS SQL Manager for InterBase and Firebird

To samo zapytanie wykonane po raz

pierwszy:
Query Performance

Prepare : 0 ms
Execute : 0 ms
Avg fetch time: 0 ms

Memory Usage

Current: 910,57 kB
Max : 914,43 kB
Buffers: 75

Database Operations

Reads : 5809
Writes : 5420
Fetches: 57682

Plan:

PLAN JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (T NATURAL, CEX INDEX (RDB$PRIMARY7)), C INDEX (RDB$PRIMARY3)), RG INDEX (KRABATGRUPA)), K INDEX (RDB$PRIMARY6)), P INDEX (RDB$PRIMARY2)), GT INDEX (RDB$PRIMARY1)), N INDEX (RDB$PRIMARY8)), H INDEX (INDEX_NAMD5))

Table Operations:
Table Name | Index reads | Non-Index reads | Updates | Deletes | Inserts
TABLE1 | 0 | 59 | 0 | 0 | 0
TABLE2 | 59 | 0 | 0 | 0 | 0
TABLE3 | 59 | 0 | 0 | 0 | 0
TABLE4 | 59 | 0 | 0 | 0 | 0
TABLE5 | 59 | 0 | 0 | 0 | 0

drugi:
Query Performance

Prepare : 0 ms
Execute : 0 ms
Avg fetch time: 0 ms

Memory Usage

Current: 898,34 kB
Max : 915,26 kB
Buffers: 75

Database Operations

Reads : 31
Writes : 31
Fetches: 1646

Plan:

PLAN JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (T NATURAL, CEX INDEX (RDB$PRIMARY7)), C INDEX (RDB$PRIMARY3)), RG INDEX (KRABATGRUPA)), K INDEX (RDB$PRIMARY6)), P INDEX (RDB$PRIMARY2)), GT INDEX (RDB$PRIMARY1)), N INDEX (RDB$PRIMARY8)), H INDEX (INDEX_NAMD5))

Table Operations:
Table Name | Index reads | Non-Index reads | Updates | Deletes | Inserts
TABLE1 | 0 | 57 | 0 | 0 | 0
TABLE2 | 57 | 0 | 0 | 0 | 0
TABLE3 | 57 | 0 | 0 | 0 | 0
TABLE4 | 57 | 0 | 0 | 0 | 0
TABLE5 | 57 | 0 | 0 | 0 | 0

trzeci:
Query Performance

Prepare : 0 ms
Execute : 0 ms
Avg fetch time: 0 ms

Memory Usage

Current: 898,34 kB
Max : 915,26 kB
Buffers: 75

Database Operations

Reads : 0
Writes : 0
Fetches: 1646

Plan:

PLAN JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (JOIN (T NATURAL, CEX INDEX (RDB$PRIMARY7)), C INDEX (RDB$PRIMARY3)), RG INDEX (KRABATGRUPA)), K INDEX (RDB$PRIMARY6)), P INDEX (RDB$PRIMARY2)), GT INDEX (RDB$PRIMARY1)), N INDEX (RDB$PRIMARY8)), H INDEX (INDEX_NAMD5))

Table Operations:
Table Name | Index reads | Non-Index reads | Updates | Deletes | Inserts
TABLE1 | 0 | 57 | 0 | 0 | 0
TABLE2 | 57 | 0 | 0 | 0 | 0
TABLE3 | 57 | 0 | 0 | 0 | 0
TABLE4 | 57 | 0 | 0 | 0 | 0
TABLE5 | 57 | 0 | 0 | 0 | 0

0

Przerobiłem na szybko aplikację tak aby korzystała z bazy SQLite (zamiast Firebird).
To samo zapytanie, na tych samych danych wykonuje się dużo szybciej...

0

Czy ja dobrze widzę, że poprzez program pytanie wykonuje się niemal natychmiast? Bo sądząc po ilości danych to nie powinno być żadnego kłopotu. Masz tu przykładowe statystyki z mojego programu gdzie tych danych masz o wiele więcej:

Query Time
------------------------------------------------
Prepare       : 0,00 ms
Execute       : 1 732,00 ms
Avg fetch time: 61,86 ms

Memory
------------------------------------------------
Current: 40 973 012
Max    : 41 106 480
Buffers: 2 048

Operations
------------------------------------------------
Read   : 11 367
Writes : 0
Fetches: 557 900
Marks  : 0


Enchanced Info:

+-------------------------------+-----------+-----------+-------------+---------+---------+---------+----------+----------+----------+
|          Table Name           |  Records  |  Indexed  | Non-Indexed | Updates | Deletes | Inserts | Backouts |  Purges  | Expunges |
|                               |   Total   |   reads   |    reads    |         |         |         |          |          |          |
+-------------------------------+-----------+-----------+-------------+---------+---------+---------+----------+----------+----------+
|T1                             |        11 |     17233 |           0 |       0 |       0 |       0 |        0 |        0 |        0 |
|T2                             |    130811 |    130810 |           0 |       0 |       0 |       0 |        0 |        0 |        0 |
|T3                             |        10 |         9 |           0 |       0 |       0 |       0 |        0 |        0 |        0 |
|T4                             |     13452 |     17233 |           0 |       0 |       0 |       0 |        0 |        0 |        0 |
|T5                             |       114 |     17233 |           0 |       0 |       0 |       0 |        0 |        0 |        0 |
|T6                             |         7 |     17233 |           0 |       0 |       0 |       0 |        0 |        0 |        0 |
+-------------------------------+-----------+-----------+-------------+---------+---------+---------+----------+----------+----------+

Ale jeśli pod programem do zarządzania bazy danych zapytanie wykonuje się tak wolno, to masz jakiś problem z bazą danych, albo dyskiem twardym. Baza może być po prostu uszkodzona. Warto by stworzyć nową bazę z tymi samymi danymi. Bo tych danych masz bardzo mało...

0
Mr.YaHooo napisał(a):
woolfik napisał(a):

Możliwe ze FB ma podobnie
Ale to już zależy od użytej biblioteki. Takie coś jak piszesz zadziała jeśli jawnie wyda się polecenie "Prepare" przed otwarciem DataSeta, czy innego komponentu. Wtedy przed jego zniszczeniem trzeba ręcznie zrobić "Unprepare". Nie wiem w czym pisze pytający, ale większość bibliotek do Firebirda przed wywołaniem zapytania robi Prepare, przed zamknięciem Unprepare. Zatem jeśli chcemy używać zapytań z parametrami należy raz zrobić Prepare(), na koniec dać Unprepare().

Ja bym odpalił problemowe zapytanie nie z poziomu programu, ale z poziomu np. IBExperta gdzie wtedy widać statystyki (ilość odczytów z poszczególnych tabel, czas przygotowania itp). I zobaczył jak to się na przy 1 razie oraz kolejnych.

Ja nie pisałem o parametrach jako parametrach ze środowiska (czyli Prepare/Unprepare, DataSet itd.) ale o parametrach bazodanowych. W samym oracle istnieje coś takiego jak prametr i możesz to nawet z sqlplusa użyć nie stosując nic innego.

0

@woolfik już rozumiem. Ale czy Firebird posiada coś takiego nie mam pojęcia. A nie udało mi się zaobserwować takiego zachowania.

1 użytkowników online, w tym zalogowanych: 0, gości: 1