Newsgroup: it.comp.software.database
Titolo: Le join sono lente

Lo so, invece di stare qui al Mac a fare prove dovrei uscire.
Mi ricollego ai thread dei giorni scorsi.
Lo sappiamo, le join sono lente. Lo dice anche Cal Henderson di Flickr:
http://www.iamcal.com/talks/flickr_php.pdf
JOIN’s are slow
- Normalised data is for sissies
- Keep multiple copies of data around
- Makes searching faster
- Have to ensure consistency in the application logic
Il mio piccolo Mac Mini con Oracle 10gR1, però, dice il contrario:
ao1 e ao2 sono copie di all_objects, 39000 righe circa ciascuna.
ao1_ao2 è:
create table ao1_ao2 as
select
	ao1.owner, ao1.object_name, ao2.object_id, ao2.created
from
	ao1
join
	ao2
on
	ao1.object_id = ao2.object_id
(la query che ho usato per i test facendo la join)
ao1, ao2 e ao1_ao2 hanno un constraint di chiave primaria su object_id,
quindi anche l'indice relativo.
- PRIMA PROVA: select di tutta la tabella ao1_ao2 e stessi dati presi
però dalla join tra ao1 e ao2:
********************************************************************************
select *
from
 ao1_ao2
call     count       cpu    elapsed       disk      query    current
    rows
------- ------  -------- ---------- ---------- ---------- ----------
----------
Parse        1      0.00       0.00          0          0          0
       0
Execute      1      0.00       0.00          0          0          0
       0
Fetch     2621      0.25       0.37          0       2873          0
   39294
------- ------  -------- ---------- ---------- ---------- ----------
----------
total     2623      0.25       0.37          0       2873          0
   39294
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
********************************************************************************
select ao1.owner, ao1.object_name, ao2.object_id, ao2.created
from
 ao1 join ao2 on ao1.object_id = ao2.object_id
call     count       cpu    elapsed       disk      query    current
    rows
------- ------  -------- ---------- ---------- ---------- ----------
----------
Parse        1      0.00       0.00          0          0          0
       0
Execute      1      0.00       0.00          0          0          0
       0
Fetch     2621      0.49       0.64        210       2068          0
   39294
------- ------  -------- ---------- ---------- ---------- ----------
----------
total     2623      0.49       0.65        210       2068          0
   39294
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 70
Rows     Row Source Operation
-------  ---------------------------------------------------
  39294  HASH JOIN  (cr=2068 pr=210 pw=210 time=318618 us)
  39295   TABLE ACCESS FULL AO2 (cr=553 pr=0 pw=0 time=97253 us)
  39295   TABLE ACCESS FULL AO1 (cr=1515 pr=0 pw=0 time=78803 us)
L'I/O logico è minore nel caso della join, ma qualcosa viene letto da
disco. Non sono riuscito ad evitare ciò. I tempi quindi sono
inevitabilmente maggiori, ma per nulla inaccettabili.
- SECONDA PROVA: come sopra, ma select di una parte dei dati.
********************************************************************************
select *
from
 ao1_ao2 where object_id between 6000 and 7000
call     count       cpu    elapsed       disk      query    current
    rows
------- ------  -------- ---------- ---------- ---------- ----------
----------
Parse        1      0.00       0.00          0          0          0
       0
Execute      1      0.00       0.00          0          0          0
       0
Fetch       36      0.03       0.01          0        306          0
     519
------- ------  -------- ---------- ---------- ---------- ----------
----------
total       38      0.03       0.01          0        306          0
     519
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 70
********************************************************************************
select ao1.owner, ao1.object_name, ao2.object_id, ao2.created
from
 ao1 join ao2 on ao2.object_id = ao1.object_id where ao1.object_id between
  6000 and 7000
call     count       cpu    elapsed       disk      query    current
    rows
------- ------  -------- ---------- ---------- ---------- ----------
----------
Parse        1      0.00       0.00          0          0          0
       0
Execute      1      0.00       0.00          0          0          0
       0
Fetch       36      0.01       0.01          0         92          0
     519
------- ------  -------- ---------- ---------- ---------- ----------
----------
total       38      0.01       0.01          0         92          0
     519
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 70
Rows     Row Source Operation
-------  ---------------------------------------------------
    519  HASH JOIN  (cr=92 pr=0 pw=0 time=18313 us)
    519   TABLE ACCESS BY INDEX ROWID AO2 (cr=11 pr=0 pw=0 time=4420 us)
    519    INDEX RANGE SCAN PK_AO2 (cr=3 pr=0 pw=0 time=661 us)(object
id 52903)
    519   TABLE ACCESS BY INDEX ROWID AO1 (cr=81 pr=0 pw=0 time=9512 us)
    519    INDEX RANGE SCAN PK_AO1 (cr=38 pr=0 pw=0 time=5302 us)(object
id 52902)
Beh questa è forte! L'I/O è *minore* nel caso della join, quindi si ha
anche minore utilizzo di CPU!
Allora non avrà per caso ragione Chris Date:
http://searchoracle.techtarget.com/generic/0,295582,sid41_gci1091031,00.html
"Join is part of the model, and the model as such can't be said to be
either fast or slow; only implementations can be said to possess any
such quality."
Bye :-)
PS: ovviamente non pensavo che le join fossero lente... volevo solo
qualche numero per rispondere con qualche dato sottomano.
-- 
Rudy
http://rdbland.blogspot.com/
e-mail a 
email.it

> such quality."
Esattamente quello di cui non tengono conto coloro che fanno certe
affermazioni; al massimo si può dire che UNA data operazione su
UN dato software è più lento/veloce rispetto a...
Ci sono una varietà di implementazioni differenti che rendono
impossibile predire la velocità di un'operazione come il join;
purtroppo come al solito si prendono a riferimento gli sql-db che
hanno la trasposizione diretta righe->record; in alcuni moderni db
neppure c'è più il record, senza contare il fatto che le stringhe
lunghe vengono codificate in rappresentazioni binarie.
Questo senza contare che l'auto-tuning renderà sempre più marginale
il ruolo del dba (favore del data modeler), e manipolare schema
logico per far andare meglio una query ci sembrerà il paleolitico.