Discussion:
optimizujme
(prestaro za odgovor)
mimix
2011-02-06 14:50:29 UTC
Permalink
Imam jednu tablicu vličine, ne znam sad točno, možda oko 5k blokova, u
DW okruženju, i u toj tablici su upisani vremenski intervali.
Znači imam kolone datum_od i datum_do, na njima je BT index i zapisi u
tablici su sortirani po njima.

Ja trebam za svaki dan u godini izvuči intervale koji u taj dan upadaju.
Imam i pomočnu tablicu 'kalendar':

select k.datum,
i.*
from intervali i,
kalendar k
where k.datum between i.datum_od and i.datum_do


I to je pre sporo. Napravio sam materijalizirani view nad time i nešto
je bolje, ali opet je sporo. "Average data blocks per key" indeksa nad
'datum' je oko 70. Tu je problem.

Ima li kakvih ideja? Model mogu presložiti. U parametre baze ne diram.
--
Milan Mimica
http://sparklet.sf.net
Gox
2011-02-07 08:59:25 UTC
Permalink
Imam 2 prijedloga.

1. Kreiraj funkciju fVratiDatum(dDatum_od, dDatum_do) return date

i koristi je

select i.*, fVratiDatum(i.datum_od, i.datum_do) Datum
from intervali i



2. Koristi sql hintove kao npr:

select /*+ RULE */ k.datum,
i.*
from intervali i,
kalendar k
where k.datum between i.datum_od and i.datum_do


Ima ih i još poglrdaj malo.


Kreiraj index i u tablici intervali na polju datum

Možda nešto pomogne.
Post by mimix
Imam jednu tablicu vličine, ne znam sad točno, možda oko 5k blokova, u
DW okruženju, i u toj tablici su upisani vremenski intervali.
Znači imam kolone datum_od i datum_do, na njima je BT index i zapisi u
tablici su sortirani po njima.
Ja trebam za svaki dan u godini izvuči intervale koji u taj dan upadaju.
select k.datum,
i.*
from intervali i,
kalendar k
where k.datum between i.datum_od and i.datum_do
I to je pre sporo. Napravio sam materijalizirani view nad time i nešto
je bolje, ali opet je sporo. "Average data blocks per key" indeksa nad
'datum' je oko 70. Tu je problem.
Ima li kakvih ideja? Model mogu presložiti. U parametre baze ne diram.
--
http://salonatenis.mojblog.hr/
mimix
2011-02-07 20:03:01 UTC
Permalink
Post by Gox
Imam 2 prijedloga.
1. Kreiraj funkciju fVratiDatum(dDatum_od, dDatum_do) return date
i koristi je
select i.*, fVratiDatum(i.datum_od, i.datum_do) Datum
from intervali i
Neće ići.
Post by Gox
select /*+ RULE */ k.datum,
i.*
from intervali i,
kalendar k
where k.datum between i.datum_od and i.datum_do
Prvo moraš znati što želiš, a onda proslijediš adekvatan hint, ne?

Zapravo, teško ću samo tako dobiti riješenje. Ja imam više uvida u
strukturu podataka. Recordset je prepun redundatnih podataka, a ni
jedna šema kompresije nije od pomoći.
--
Milan Mimica
http://sparklet.sf.net
GD
2011-02-09 19:43:54 UTC
Permalink
Post by Gox
Imam 2 prijedloga.
1. Kreiraj funkciju fVratiDatum(dDatum_od, dDatum_do) return date
i koristi je
select i.*, fVratiDatum(i.datum_od, i.datum_do) Datum
from intervali i
select /*+ RULE */ k.datum,
i.*
from intervali i,
kalendar k
where k.datum between i.datum_od and i.datum_do
Ima ih i jo¹ poglrdaj malo.
Znas li ti sto je to rule hint i cemu to sluzi?
Danas predloziti nekome RBO u smislu "probaj, mozda pomogne" totalni je
promasaj (premda jos radi) i pokazuje nepoznavanje teme.

Za OP-a: nemam odgovor na pitanje :)

Pozdrav
mimix
2011-02-09 20:51:01 UTC
Permalink
Post by GD
Danas predloziti nekome RBO u smislu "probaj, mozda pomogne" totalni je
promasaj (premda jos radi) i pokazuje nepoznavanje teme.
Ali kad radi, ponekad. Postoje SQL-i koje CBO jednostavno nikako
ne uspjeva posložiti idealno, a idealno je onako kao ih složi RBO, jer
su za njega i pisani.
Smješno je koliko puta sam dao +rule samo da vidim kako bi SQL zapravo
trebao ići pa da ga mogu hintati.
--
Milan Mimica
http://sparklet.sf.net
GD
2011-02-10 14:23:39 UTC
Permalink
Post by mimix
Post by GD
Danas predloziti nekome RBO u smislu "probaj, mozda pomogne" totalni je
promasaj (premda jos radi) i pokazuje nepoznavanje teme.
Ali kad radi, ponekad. Postoje SQL-i koje CBO jednostavno nikako
ne uspjeva posloŸiti idealno, a idealno je onako kao ih sloŸi RBO, jer
su za njega i pisani.
Smje¹no je koliko puta sam dao +rule samo da vidim kako bi SQL zapravo
trebao iæi pa da ga mogu hintati.
Naravno, no rule trebao biti zadnji, a ne prvi pokusaj optimizacije. Ako ni
zbog cega drugoga, onda zato sto danas vise nije podrzan, a sutra ga
jednostavno vise nece biti.

Pozdrav
originalni poster
2011-02-18 17:17:48 UTC
Permalink
Post by mimix
Imam jednu tablicu vličine, ne znam sad točno, možda oko 5k blokova, u
DW okruženju, i u toj tablici su upisani vremenski intervali.
Znači imam kolone datum_od i datum_do, na njima je BT index i zapisi u
tablici su sortirani po njima.
Ja trebam za svaki dan u godini izvuči intervale koji u taj dan upadaju.
select k.datum,
i.*
from intervali i,
kalendar k
where k.datum between i.datum_od and i.datum_do
I to je pre sporo. Napravio sam materijalizirani view nad time i nešto
je bolje, ali opet je sporo. "Average data blocks per key" indeksa nad
'datum' je oko 70. Tu je problem.
Ima li kakvih ideja? Model mogu presložiti. U parametre baze ne diram.
Treba nam verzija baze, veličina tablica,tip
tablica(partitioning),explain plan i podaci
selektivnosti indeksa koji se koriste-ako se koriste.
Ovo je neki minumim minimuma da ti se pokusa pomoci
na daljinu pomocu remote carobne kristalne kugle.
mimix
2011-02-21 21:01:18 UTC
Permalink
Post by originalni poster
Treba nam verzija baze, veličina tablica,tip
tablica(partitioning),explain plan i podaci
selektivnosti indeksa koji se koriste-ako se koriste.
Aj super. Evo ti:

10.2.0.5

Znači ovo je neoptimalni plan. (Nemam pojma zašto radi SS na indeksu,
nisam prije primjetio.)
bi.kalendar je tablica s jednim retkom za svaki dan u godini.

select *
from bi.intervali u,
bi.kalendar k
where k.day between u.datum_od and u.datum_do
and k.day between '01052010' and '31102010';

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1301214371

----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25508 | 9M| 4126 (43)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | MERGE JOIN | | 25508 | 9M| 4126 (43)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | INTERVALI | 55140 | 8400K| 3085 (24)| 00:00:01 |
|* 4 | INDEX SKIP SCAN | I_INTERVALI_DATUM_OD_DO | 55140 | | 220 (52)| 00:00:01 |
|* 5 | FILTER | | | | | |
|* 6 | SORT JOIN | | 185 | 46065 | 10 (40)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| KALENDAR | 185 | 46065 | 8 (25)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | I_KALENDAR_DAY | 185 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter(TO_DATE('01052010')<=TO_DATE('31102010'))
4 - access("U"."DATUM_DO">='01052010' AND "U"."DATUM_OD"<='31102010')
filter("U"."DATUM_DO">='01052010')
5 - filter("K"."DAY"<="U"."DATUM_DO")
6 - access("K"."DAY">="U"."DATUM_OD")
filter("K"."DAY">="U"."DATUM_OD")
8 - access("K"."DAY">='01052010' AND "K"."DAY"<='31102010')

I neki statistički podaci:

SQL> select column_name, num_distinct
2 from sys.user_tab_col_statistics
3 where table_name = 'INTERVALI'
4 and column_name in ('DATUM_OD', 'DATUM_DO');

COLUMN_NAME NUM_DISTINCT
------------------------------ ------------
DATUM_OD 140
DATUM_DO 150

SQL> select avg(datum_do - datum_od)
2 from intervali;

AVG(DATUM_DO-DATUM_OD)
----------------------
33,278067

SQL> select index_type, table_name, blevel, leaf_blocks,
2 distinct_keys, avg_leaf_blocks_per_key,
3 avg_data_blocks_per_key, clustering_factor
4 from sys.user_indexes
5 where index_name = 'I_INTERVALI_DATUM_OD_DO';

INDEX_TYPE TABLE_NAME BLEVEL LEAF_BLOCKS
---------------------- -------------------- --------- -----------
NORMAL INTERVALI 2 750
...
DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR
------------- ----------------------- ----------------------- -----------------
646 1 42 27385


Bolju sliku o podacima dobiješ kada napraviš materijalizirani view
od prvog querija i indeksiraš datum iz kalendara.

CREATE MATERIALIZED VIEW BI_MV_INTERVALI
...
AS
select *
from bi.intervali u,
bi.kalendar k
where k.day between u.datum_od and u.datum_do
and k.day between '01012008' and '31122011';

SQL> select num_rows, blocks
2 from sys.user_tab_statistics
3 where table_name = 'BI_MV_INTERVALI';

NUM_ROWS BLOCKS
--------- ---------
2960284 67665

SQL> select index_type, table_name, blevel, leaf_blocks,
2 distinct_keys, avg_leaf_blocks_per_key,
3 avg_data_blocks_per_key, clustering_factor
4 from sys.user_indexes
5 where index_name = 'I_BI_MV_INTERVALI_DATUM';

INDEX_TYPE TABLE_NAME BLEVEL LEAF_BLOCKS
--------------------------- ------------------- --------- -----------
NORMAL BI_MV_INTERVALI 2 7909

DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY CLUSTERING_FACTOR
------------- ----------------------- ----------------------- -----------------
1095 7 90 99488


E sad. AVG_LEAF_BLOCKS_PER_KEY se lako smanji kompresijom indeksa. Ovaj
AVG_DATA_BLOCKS_PER_KEY je problematičan.
--
Milan Mimica
http://sparklet.sf.net
originalni poster
2011-02-21 23:00:36 UTC
Permalink
Post by mimix
Post by originalni poster
Treba nam verzija baze, veličina tablica,tip
tablica(partitioning),explain plan i podaci
selektivnosti indeksa koji se koriste-ako se koriste.
Znači ovo je neoptimalni plan.
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1301214371
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25508 | 9M| 4126 (43)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | MERGE JOIN | | 25508 | 9M| 4126 (43)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | INTERVALI | 55140 | 8400K| 3085 (24)| 00:00:01 |
|* 4 | INDEX SKIP SCAN | I_INTERVALI_DATUM_OD_DO | 55140 | | 220 (52)| 00:00:01 |
|* 5 | FILTER | | | | | |
|* 6 | SORT JOIN | | 185 | 46065 | 10 (40)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| KALENDAR | 185 | 46065 | 8 (25)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | I_KALENDAR_DAY | 185 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
ok, sve kaj si postao su naravno korisne informacije,ali naravno s
obzirom na ovaj plan koji bi se navodno trebao koristiti prilikom
izvođenja upita,
koliki je stvarni execution time tog upita....ovaj plan sugerira vrlo
kratko vrijeme- a.k.a. 00:00:01
mimix
2011-02-21 23:49:22 UTC
Permalink
Post by originalni poster
Post by mimix
Post by originalni poster
Treba nam verzija baze, veličina tablica,tip
tablica(partitioning),explain plan i podaci
selektivnosti indeksa koji se koriste-ako se koriste.
Znači ovo je neoptimalni plan.
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1301214371
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25508 | 9M| 4126 (43)| 00:00:01 |
|* 1 | FILTER | | | | | |
| 2 | MERGE JOIN | | 25508 | 9M| 4126 (43)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | INTERVALI | 55140 | 8400K| 3085 (24)| 00:00:01 |
|* 4 | INDEX SKIP SCAN | I_INTERVALI_DATUM_OD_DO | 55140 | | 220 (52)| 00:00:01 |
|* 5 | FILTER | | | | | |
|* 6 | SORT JOIN | | 185 | 46065 | 10 (40)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| KALENDAR | 185 | 46065 | 8 (25)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | I_KALENDAR_DAY | 185 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
ok, sve kaj si postao su naravno korisne informacije,ali naravno s
obzirom na ovaj plan koji bi se navodno trebao koristiti prilikom
izvođenja upita,
koliki je stvarni execution time tog upita....ovaj plan sugerira vrlo
kratko vrijeme- a.k.a. 00:00:01
Da, inače ide veći raspon datuma, i query se još malo zakomplicira, ali
ovo je jezgra i traje višesrtuko dulje od jedne sekunde (tipa 3-4 sekunde).
Poanta je da je pre sporo, koliko god relativno brzo bilo.

Prilično sam siguran da ne mogu ovako preko useneta objasniti koliko se
ovdje radi o generičkom slučaju. Tablica sa relativno širokim rasponima
datuma koja se spaja na svaki dan u godini. To bi se trebalo riješavati
po nekom receptu.
--
Milan Mimica
http://sparklet.sf.net
GD
2011-02-22 11:20:19 UTC
Permalink
Post by mimix
Treba nam verzija baze, velicina tablica,tip
tablica(partitioning),explain plan i podaci
selektivnosti indeksa koji se koriste-ako se koriste.
10.2.0.5
Znaci ovo je neoptimalni plan. (Nemam pojma zasto radi SS na indeksu,
nisam prije primjetio.)
bi.kalendar je tablica s jednim retkom za svaki dan u godini.
select *
from bi.intervali u,
bi.kalendar k
where k.day between u.datum_od and u.datum_do
and k.day between '01052010' and '31102010';
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1301214371
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows
| Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | |
25508 | 9M| 4126 (43)| 00:00:01 |
|* 1 | FILTER | |
| | | |
| 2 | MERGE JOIN | |
25508 | 9M| 4126 (43)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID | INTERVALI |
55140 | 8400K| 3085 (24)| 00:00:01 |
|* 4 | INDEX SKIP SCAN | I_INTERVALI_DATUM_OD_DO |
55140 | | 220 (52)| 00:00:01 |
|* 5 | FILTER | |
| | | |
|* 6 | SORT JOIN | |
185 | 46065 | 10 (40)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| KALENDAR |
185 | 46065 | 8 (25)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | I_KALENDAR_DAY |
185 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------
---------------------------------------------------
1 - filter(TO_DATE('01052010')<=TO_DATE('31102010'))
4 - access("U"."DATUM_DO">='01052010' AND "U"."DATUM_OD"<='31102010')
filter("U"."DATUM_DO">='01052010')
5 - filter("K"."DAY"<="U"."DATUM_DO")
6 - access("K"."DAY">="U"."DATUM_OD")
filter("K"."DAY">="U"."DATUM_OD")
8 - access("K"."DAY">='01052010' AND "K"."DAY"<='31102010')
Kojeg tipa je kolona datum u tablici kalendar i kolone datum_od, datum_do u
intervali? Mozes li poslati desc obje tablice, rekao bih da se dogada
implicitna konverzija tipova.
Ako su kolone koje predstavljaju datume tipa varchar2, zasto datum nije
formiran u obliku YYYYMMDD u kojem slucaju bi vrijednosti bile "pravilno"
sortirane u indeksima?
Je li index i_intervali_od_do kompozitni indeks s kolonom datum_od na prvom
mjestu? Skip scan mozda znaci da bi bilo korisno imati po jedan indeks na
svakoj od te dvije kolone.

Pozdrav
mimix
2011-02-22 20:19:33 UTC
Permalink
Post by GD
Kojeg tipa je kolona datum u tablici kalendar i kolone datum_od, datum_do u
intervali? Mozes li poslati desc obje tablice, rekao bih da se dogada
implicitna konverzija tipova.
Svaki datum je DATE, 100%.

Uvijek koristim 'ddmmyyyy' kada moram brzo otipkati i nikad problema.
Valjda je tako naštimano. Taj string se pretvori u date, implicirno,
prije izvođenja querija.
Post by GD
Je li index i_intervali_od_do kompozitni indeks s kolonom datum_od na prvom
mjestu?
Je... ili je možda datum_do na prvom mejstu što objašnjava SS. Trebam
provjeriti.
--
Milan Mimica
http://sparklet.sf.net
GD
2011-02-23 19:07:37 UTC
Permalink
Post by mimix
Post by GD
Kojeg tipa je kolona datum u tablici kalendar i kolone datum_od, datum_do u
intervali? Mozes li poslati desc obje tablice, rekao bih da se dogada
implicitna konverzija tipova.
Svaki datum je DATE, 100%.
Uvijek koristim 'ddmmyyyy' kada moram brzo otipkati i nikad problema.
Valjda je tako naštimano. Taj string se pretvori u date, implicirno,
prije izvođenja querija.
Dobro, nagadam u cemu bi mogao biti problem, konverzije tipova (npr.
kada u bind varijabli dode pogresan tip podatka, sto ovdje vjerojatno
nije slucaj) ponekad mogu uzrokovati drugaciji "run-time" exec plan od
onoga kojeg vidis sa "explain plan".

S druge strane, prema planu (sto ne mora odgovarati stvarnosti) upit
vraca 25.000 redaka, sto je relativno puno i uzrokuje puno single block
readova pa mora trajati odredeno vrijeme.

Pozdrav

Loading...