ďťż
 
[mysql] (4.1 lub nowszy) pobieranie =?UTF-8?Q?rekord=C3=B3w?="minimalnych" ďťż
 
[mysql] (4.1 lub nowszy) pobieranie =?UTF-8?Q?rekord=C3=B3w?="minimalnych"
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

[mysql] (4.1 lub nowszy) pobieranie =?UTF-8?Q?rekord=C3=B3w?="minimalnych"



hubert depesz lubaczewski - 13-02-2007 00:04
[mysql] (4.1 lub nowszy) pobieranie =?UTF-8?Q?rekord=C3=B3w?="minimalnych"
  hej
1. zajrzałem do faq - nie widzę tam tego
2. wiem jak zapisać w postgresie, wiem jak zapisać (nieoptymalnie) w
mysql'u.

szczegóły:
tabelka "t" o kolumnach: id, kod, kiedy

id jest kluczem podstawowym, dodatkowo mamy pewność, że kombinacja (kod,
kiedy) jest unikatowa.

dane są zasadniczo codziennie (kiedy ma granulację 1 dnia), ale nie
codziennie dla wszystkich kodów.

chciałbym dostać listę rekordów dla wszystkich możliwych kodów, z
pierwszym "kiedy" po określonej dacie.

czyli. dla tabelki:
id | kod | kiedy
----+-----+------------
1 | a | 2007-02-01
2 | b | 2007-02-02
3 | c | 2007-01-31
4 | b | 2007-02-17

i warunkiem od daty '2007-02-01' chcę dostać:
id | kod | kiedy
----+-----+------------
1 | a | 2007-02-01
2 | b | 2007-02-02

(rekord z id 3 nie, bo jest wcześniej niż 2006-02-01, a rekord z id = 4
nie, bo jest później, ale jest rekord 2 który jest wcześniej).

mam nadzieję, że to jasne.

jak to zrobić optymalnie w mysql'u? jeśli da się lepiej w wersji 5.0 czy
5.1 - fajnie, ale proszę o zaznaczenie tego od której wersji to
zadziała.

depesz

--
quicksil1er: "postgres is excellent, but like any DB it requires a
highly paid DBA. here's my CV!" :)
http://www.depesz.com/ - blog dla ciebie (i moje CV)





Michal Jankowski - 13-02-2007 00:04

  hubert depesz lubaczewski <depesz@depesz.com> writes:

> 2. wiem jak zapisać w postgresie, wiem jak zapisać (nieoptymalnie) w
> mysql'u.

A mógłbyś - dla potomności - obie wersje podać?

MJ




hubert depesz lubaczewski - 13-02-2007 00:04

  On 2007-02-12, Michal Jankowski <michalj@fuw.edu.pl> wrote:
>> 2. wiem jak zapisać w postgresie, wiem jak zapisać (nieoptymalnie) w
>> mysql'u.
> A mógłbyś - dla potomności - obie wersje podać?

w postgresie:
select distinct on (kod) * from t where kiedy >= '2007-02-01' order by
kod, kiedy asc;

w mysql'u, ale raczej nieoptymalnie:
select t1.* from t t1 where t1.kiedy >= '2007-02-01' and not exists
(select * from t t2 where t2.kod = t1.kod and t2.kiedy < t1.kiedy and
t2.kiedy >= '2007-02-01');

depesz

--
quicksil1er: "postgres is excellent, but like any DB it requires a
highly paid DBA. here's my CV!" :)
http://www.depesz.com/ - blog dla ciebie (i moje CV)




Rafalsxat - 13-02-2007 00:04
=?UTF-8?Q?Re:_=5Bmysql=5D_=284.1_lub_nowszy=29_pob?= =?UTF-8?Q?ieranie_rekord=C3=B3w__=22minimalnych=22?=
  > czyli. dla tabelki:
> id | kod | kiedy
> ----+-----+------------
> 1 | a | 2007-02-01
> 2 | b | 2007-02-02
> 3 | c | 2007-01-31
> 4 | b | 2007-02-17
>
> i warunkiem od daty '2007-02-01' chcę dostać:
> id | kod | kiedy
> ----+-----+------------
> 1 | a | 2007-02-01
> 2 | b | 2007-02-02
>
> (rekord z id 3 nie, bo jest wcześniej niż 2006-02-01, a rekord z id = 4
> nie, bo jest później, ale jest rekord 2 który jest wcześniej).

czysta mysl, moze dziala:

select *
from (select *
from t
where kiedy >= '2007-02-01'
order by kiedy asc)
group by kod

pozdr
Raf

--
Archiwum grupy: http://niusy.onet.pl/pl.comp.bazy-danych





hubert depesz lubaczewski - 13-02-2007 00:04

  On 2007-02-12, Rafalsxat <gonzak@op.pl> wrote:
> select *
> from (select *
> from t
> where kiedy >= '2007-02-01'
> order by kiedy asc)
> group by kod

hmm .. działa.
wygląda na to, że group by w tym przypadku działa tak jak distinct on.

czy to jest jakoś gdzieś udokumentowane?
i dodatkowo - czy taki "group by" jest robiony przed czy po sortowaniu?

depesz

--
quicksil1er: "postgres is excellent, but like any DB it requires a
highly paid DBA. here's my CV!" :)
http://www.depesz.com/ - blog dla ciebie (i moje CV)




Michal Jankowski - 13-02-2007 00:04

  hubert depesz lubaczewski <depesz@depesz.com> writes:

> hmm .. działa.
> wygląda na to, że group by w tym przypadku działa tak jak distinct on.

To jest znany ficzer mysql, że

select c1, c2 from t group by c1;

działa na kształt

select c1, first(c2) from t group by c1;

albo inaczej

select distinct on (c1) c1, c2 from t;

> czy to jest jakoś gdzieś udokumentowane?

A czort go wie 8-).

MJ




Maciek Dobrzanski - 13-02-2007 00:04

  "hubert depesz lubaczewski" <depesz@depesz.com> wrote in message
news:hbd6a4-p5p.ln1@xxx.home.depesz.com...

>> select *
>> from (select *
>> from t
>> where kiedy >= '2007-02-01'
>> order by kiedy asc)
>> group by kod
>
> hmm .. działa.
> wygląda na to, że group by w tym przypadku działa tak jak distinct on.
>
> czy to jest jakoś gdzieś udokumentowane?

A mnie swoją drogą przyszedł do głowy inny, chytry plan wynikający ze
sposobu w jaki MySQL korzysta z danych i z indeksów. Na starcie mamy tabelę
w najprostszej postaci, wypełnioną kilkudziesięcioma tysiącami wierszy
(dokładnie 27748).

CREATE TABLE `t12` (
-> `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
-> `kod` char(1) NOT NULL,
-> `kiedy` date NOT NULL);

Dla testów i lepszego obrazu wyników usunąłem z niej wszystkie te, które
spełniają:

kod = 'c' AND kiedy >= '2007-02-01'
kod = 'b' AND kiedy BETWEEN '2007-02-01' AND '2007-02-03'

Oczywiście w najprostszej formie zapytanie nie zwróci oczekiwanych wyników,
tj.

SELECT * FROM t12 WHERE kiedy >= '2007-02-01' GROUP BY kod;

+----+-----+------------+
| id | kod | kiedy |
+----+-----+------------+
| 8 | a | 2007-02-04 |
| 3 | b | 2007-03-12 |
| 15 | d | 2007-02-01 |
+----+-----+------------+

Dane w `id` czy `kiedy` są "przypadkowe". Można więc spróbować się
posiłkować indeksem, który jako taki jest posortowany:

ALTER TABLE t12 ADD INDEX k_kiedy_kod (kiedy, kod);

Jednak nadal nie ma rezutlatów:

SELECT * FROM t12 WHERE kiedy >= '2007-02-01' GROUP BY kod;
+----+-----+------------+
| id | kod | kiedy |
+----+-----+------------+
| 8 | a | 2007-02-04 |
| 3 | b | 2007-03-12 |
| 15 | d | 2007-02-01 |
+----+-----+------------+

Dlaczego?

EXPLAIN SELECT * FROM t12 WHERE kiedy >= '2007-02-01' GROUP BY kod\G
id: 1
select_type: SIMPLE
table: t12
type: ALL
possible_keys: k_kiedy_kod
key: NULL
key_len: NULL
ref: NULL
rows: 28050
Extra: Using where; Using temporary; Using filesort

Poprostu indeks nie jest wykorzystany. Pomagam więc optymalizatorowi.

EXPLAIN SELECT * FROM t12 FORCE INDEX (k_kiedy_kod) WHERE kiedy >=
'2007-02-01' GROUP BY kod\G

id: 1
select_type: SIMPLE
table: t12
type: range
possible_keys: k_kiedy_kod
key: k_kiedy_kod
key_len: 3
ref: NULL
rows: 18469
Extra: Using where; Using temporary; Using filesort

Dobrze. A jak prezentuje się wynik tego zapytania?

SELECT * FROM t12 FORCE INDEX (k_kiedy_kod) WHERE kiedy >= '2007-02-01'
GROUP BY kod;

+-----+-----+------------+
| id | kod | kiedy |
+-----+-----+------------+
| 162 | a | 2007-02-01 |
| 26 | b | 2007-02-03 |
| 15 | d | 2007-02-01 |
+-----+-----+------------+

Czyli dokładnie to, co jest oczekiwane. Pierwszy w kolejności po dacie wpis
dla każdego kodu, jeśli data jest późniejsza niż '2007-02-01'. MySQL
"przejechał się" po posortowanym wg. naszego życzenia indeksie i w tej
dokładnie kolejności wyciągnął dane.

Różnica w wydajności obu wersji?

Czas wykonywania:
Moja
0.14s

Rafalsxat
0.29s

Operacje:
Moja
| Handler_read_key | 1 |
| Handler_read_next | 17993 |
| Handler_read_rnd | 3 |
| Handler_read_rnd_next | 5 |
| Handler_write | 17993 |

Rafalsxat
| Handler_read_rnd | 3 |
| Handler_read_rnd_next | 46050 |
| Handler_write | 35986 |

Oczywiście moja wersja nie jest tak uniwersalna, bo np. nie da się wyciągnąć
najstarszych wpisów. No i nie ma gwarancji, że wraz z wersją bazy coś się
nie zmieni.

Pozdrawiam,
Maciek




Maciek Dobrzanski - 13-02-2007 00:04

  "Maciek Dobrzanski" <svc.usenet@posterus.com> wrote in message
news:eqqmld$o4t$1@garfield.posterus.com...

> SELECT * FROM t12 FORCE INDEX (k_kiedy_kod) WHERE kiedy >= '2007-02-01'
> GROUP BY kod;

Co ciekawe przy silniku InnoDB optymalizator sam wybiera wykorzystanie tego
indeksu bez dodatkowego przymuszania. Ma to zapewne związek z tym, że koszt
dostępu do danych kolumny `id` poprzez indeks `k_kiedy_kod` jest w zasadzie
zerowy.

Maciek
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • effulla.pev.pl
  • comp
    [mysql] =?ISO-8859-2?Q?Za=E6mienie=2E=2E=2E_jak_wy=B6wietli=E6?==?ISO-8859-2?Q?=2E=2E=2E?= [mysql] =?ISO-8859-2?Q?wielko=B6=E6_bazy_a_stabilno=B6=E6=2C?==?ISO-8859-2?Q?_podzia=B3_du=BFej_bazy_a_powi=B1zania_tabel?= [mysql 4.0.x] przenoszenie kolum =?ISO-8859-2?Q?mi=EAdzy_bazam?==?ISO-8859-2?Q?i_cd_=2E=2E=2E_?= [MySQL] =?ISO-8859-2?Q?z=B3=B1czenie_tabeli_u=BFytkownik_i?==?ISO-8859-2?Q?_zdj=EAcia_z_wyborem_zdj=EAcia_domy=B6lnego?= [MySQL] Jak =?ISO-8859-2?Q?wpisa=E6_do_tabeli_pozycje_dl?==?ISO-8859-2?Q?a_wierszy_gdybym_te_wiersze_wybiera=B3_w_ok?== ?ISO-8859-2?Q?re=B6lonej_kolejno=B6ci_=3F?= Gdzie MySQL 4.1, a gdzie 5.0? [MySQL 4.0...4.1] zabezpieczenie przed =?ISO-8859-2?Q?jednoczesn?==?ISO-8859-2?Q?=B1_edycj=B1?= [MS SQL] "set names" (mySQL) w MS SQL [mysql 5.x] jak =?ISO-8859-2?Q?zrealizowa=E6_zapytanie=3F_cz?==?ISO-8859-2?Q?yli_podzapytanie_i_wi=EAcej_ni=BF_jeden_rz=B1? ==?ISO-8859-2?Q?d_wynik=F3w?= MySQL - jak =?ISO-8859-2?Q?wyeksportowa=E6_zawarto=B6=E6_wie?==?ISO-8859-2?Q?lkiej_tabeli?=
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • lisinski.htw.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