ďťż
 
sąsiednie rekordy ďťż
 
sąsiednie rekordy
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

sąsiednie rekordy



Paweł - 13-11-2006 00:45
sąsiednie rekordy
  Witam !

Na serwerze znajduje się baza MySQL 3.23.
W niej jest tabela mająca wielkość 400 MB składająca się z kilkudziesięciu
tysięcy rekordów.
Załóżmy dla uproszczenia, że tabela ma dwie kolumny "Id" (autoinkrement,
klucz podstawowy) i "ABC"
Do bazy danych wysyłane są ze skryptu PHP tylko dwa rodzaje zapytań:
Np.
SELECT * FROM `TABELA' WHERE Id > 30000 AND ABC != 'NULL' LIMIT 0 , 1
i
SELECT * FROM `TABELA' WHERE Id < 30000 AND ABC != 'NULL' ORDER BY Id
DESC LIMIT 0 , 1

Jak łatwo się zorientować chodzi o znalezienie najbliższego rekordu względem
danego ( w przykładzie o numerze 30000) zawierającego jakieś dane kolumnie
ABC. W pierwszym przypadku szukane są rekordy o Id większym a w drugim o Id
mniejszym.
Problem polega na tym, że pierwsze zapytanie wykonuje się 0.002 sek. a
drugie 10 sek.

Zastąpiłem więc to drugie zapytanie dwoma:
SELECT MAX(Id) FROM `TABELA' WHERE Id < 30000 AND ABC != 'NULL'
SELECT * FROM `TABELA' WHERE Id =.....

Teraz wykonuje się to około 1 sek. Jednak to dla mnie nadal za długo.
Czy jest jakiś sposób aby przyspieszyć wyszukiwanie sąsiednich rekordów ?

Paweł





Grzegorz Danowski - 13-11-2006 00:45

  Użytkownik "Paweł" <pawel.neo@neostrada.pl> napisał w wiadomości
news:ehqo41$i28$1@nemesis.news.tpi.pl...
> Witam !
>
> Na serwerze znajduje się baza MySQL 3.23.
> W niej jest tabela mająca wielkość 400 MB składająca się z kilkudziesięciu
> tysięcy rekordów.
> Załóżmy dla uproszczenia, że tabela ma dwie kolumny "Id" (autoinkrement,
> klucz podstawowy) i "ABC"
> Do bazy danych wysyłane są ze skryptu PHP tylko dwa rodzaje zapytań:
> Np.
> SELECT * FROM `TABELA' WHERE Id > 30000 AND ABC != 'NULL' LIMIT 0 , 1
> i
> SELECT * FROM `TABELA' WHERE Id < 30000 AND ABC != 'NULL' ORDER BY
> Id DESC LIMIT 0 , 1
>
> Jak łatwo się zorientować chodzi o znalezienie najbliższego rekordu
> względem danego ( w przykładzie o numerze 30000) zawierającego jakieś dane
> kolumnie ABC. W pierwszym przypadku szukane są rekordy o Id większym a w
> drugim o Id mniejszym.
> Problem polega na tym, że pierwsze zapytanie wykonuje się 0.002 sek. a
> drugie 10 sek.
>
> Zastąpiłem więc to drugie zapytanie dwoma:
> SELECT MAX(Id) FROM `TABELA' WHERE Id < 30000 AND ABC != 'NULL'
> SELECT * FROM `TABELA' WHERE Id =.....
>
> Teraz wykonuje się to około 1 sek. Jednak to dla mnie nadal za długo.
> Czy jest jakiś sposób aby przyspieszyć wyszukiwanie sąsiednich rekordów ?

Może użyj nieco zmodyfikowanego wyszukiwania binarnego? Oczywiście po
stronie php. Coś w stylu:

<pseudo kod>
int myValue = 30000
int currId = 0
int step = myValue / 2

Loop
currId = currId + step
record = Select Id From 'Tabela' Where Id < currId And Id >= myValue
Limit 0, 1

if step = 1 And record Is Not Null
return currId
else
step = step / 2

if record Is Null
currId = currId - step
else
currId = currId + step
End Loop
</pseudo kod>

Jak Ci się uda zaimplementować, to podziel się wynikami na grupie. Wg mojej
oceny, dla 30 tys. rekordów wykona się nie więcej niż 15 przebiegów pętli,
czyli czas całkowity będzie mniejszy od 15 * 0.002 = 0.03, plus wymiana
danych z php, ale trudno mi ocenić jaki jest jego narzut.

Aczkolwiek nie wiem czy nie wystarczy dodać dodatkowego indeksu na Id
posortowanego malejącą, wówczas ten Twój drugi selekt będzie szybszy.

Pozdrawiam
Grzegorz




Michał Kuratczyk - 13-11-2006 00:45

  Grzegorz Danowski wrote:
> Może użyj nieco zmodyfikowanego wyszukiwania binarnego? Oczywiście po
> stronie php.
Mam ochotę coś odpisać, ale jeszcze nie doszedłem do siebie. To jest chyba
najbardziej absurdalny pomysł jaki widziałem w odniesieniu do baz danych.

--
Michał Kuratczyk




Grzegorz Danowski - 13-11-2006 00:45

  Użytkownik "Michał Kuratczyk" <kura@lj.pl> napisał w wiadomości
news:ehsoou$2o2d$2@news2.ipartners.pl...
>> Może użyj nieco zmodyfikowanego wyszukiwania binarnego? Oczywiście po
>> stronie php.
> Mam ochotę coś odpisać, ale jeszcze nie doszedłem do siebie. To jest chyba
> najbardziej absurdalny pomysł jaki widziałem w odniesieniu do baz danych.

Zgadzam się, że moja propozycja jest nieco niekonwencjonalna (mało sql-owa),
bo i oczekiwany wynik jest mało sql-owy (jedna liczba a nie zbiór rekordów),
ale wg mojej oceny jest bardzo wydajna. Zaproponuj coś w czystym sql-u, co
będzie bardziej wydajne i wówczas Paweł porówna oba rozwiązania i zamieści
na grupie z korzyścią dla kolejnych pytaczy. Być może wystarczy dodać indeks
posortowany malejącą, ale taki pomysł też zapodałem pytaczowi.

Pozdrawiam
Grzegorz





Michał Kuratczyk - 13-11-2006 00:45

  Grzegorz Danowski wrote:
> Zgadzam się, że moja propozycja jest nieco niekonwencjonalna (mało
> sql-owa), bo i oczekiwany wynik jest mało sql-owy (jedna liczba a nie
> zbiór rekordów), ale wg mojej oceny jest bardzo wydajna. Zaproponuj coś w
> czystym sql-u, co będzie bardziej wydajne i wówczas Paweł porówna oba
> rozwiązania i zamieści na grupie z korzyścią dla kolejnych pytaczy. Być
> może wystarczy dodać indeks posortowany malejącą, ale taki pomysł też
> zapodałem pytaczowi.
Nie zaproponuję rozwiązania, bo nie znam dobrze MySQLa (w Oracle można to
zrobić funkcjami analitycznymi LEAD/LAG, które służą dokładnie do
zaglądania w poprzedni/następny rekord), ale to jeszcze nie powód, żeby
ludzi namawiać do robienia takich rzeczy.
To mniej więcej tak, jakby na pytanie "czemu mój samochód nie jest w stanie
rozpędzić się powyżej 100km/h" odpowiedzieć "kup sobie lawetę, bo ona nawet
z tym samochodem na pace więcej wyciągnie". No niby jest to jakieś
rozwiązanie, ale jednak bardzo specyficzne... :->

PS Podejrzewam, że indeks malejący załatwi sprawę.
--
Michał Kuratczyk




Grzegorz Danowski - 13-11-2006 00:45

  Użytkownik "Michał Kuratczyk" <kura@lj.pl> napisał w wiadomości
news:ehsst9$2r79$1@news2.ipartners.pl...
>> Zgadzam się, że moja propozycja jest nieco niekonwencjonalna (..)
>> Zaproponuj coś w
>> czystym sql-u, co będzie bardziej wydajne i wówczas Paweł porówna oba
>> rozwiązania i zamieści na grupie z korzyścią dla kolejnych pytaczy. Być
>> może wystarczy dodać indeks posortowany malejącą, ale taki pomysł też
>> zapodałem pytaczowi.

> Nie zaproponuję rozwiązania, bo nie znam dobrze MySQLa (w Oracle można to
> zrobić funkcjami analitycznymi LEAD/LAG, które służą dokładnie do
> zaglądania w poprzedni/następny rekord),

Znam MySQL 3.3 tylko z opowiadań, ale nie sądzę by znajdowały się tam takowe
funkcje.

> ale to jeszcze nie powód, żeby
> ludzi namawiać do robienia takich rzeczy.

Ja nikogo nie namawiam, zresztą zrobienie bezbłędnego wyszukiwania binarnego
nie jest takie proste - badania wskazują, że większość programistów nie
potrafi od razu poprawnie zaimplementować algorytmu wyszukiwania binarnego
(na pewno i ja w swym pseudo kodzie, np. to nie napisałem, że wynik step / 2
powinien być zaokrąglany w górę :-).

> To mniej więcej tak, jakby na pytanie "czemu mój samochód nie jest w
> stanie
> rozpędzić się powyżej 100km/h" odpowiedzieć "kup sobie lawetę, bo ona
> nawet
> z tym samochodem na pace więcej wyciągnie". No niby jest to jakieś
> rozwiązanie, ale jednak bardzo specyficzne... :->

Ok. Ale w sytuacji gdy za pomocą czystego sql-a mamy wynik po 1 sekundzie, a
w mojej propozycji będzie pewnie po 0,03 to korzyść jest istotna. Czyli jak
klientowi zależy na czasie i będzie chciał się dostarczyć samochód z
Warszawy do Pekinu, to lepiej zaproponować mu transport drogą lotniczą, bo w
ten sposób transport będzie trwał kilkadziesiąt razy krócej niż gdyby
samochód przemieszczał się w sposób
najbardziej naturalny dla niego, czyli na własnych kołach :-).

> PS Podejrzewam, że indeks malejący załatwi sprawę.

Z tym podejrzeniem jesteśmy zgodni, czekamy więc na wyniki Pawła.

Pozdrawiam
Grzegorz




Paweł - 13-11-2006 00:45

 
> Jak Ci się uda zaimplementować, to podziel się wynikami na grupie. Wg
> mojej
> oceny, dla 30 tys. rekordów wykona się nie więcej niż 15 przebiegów pętli,
> czyli czas całkowity będzie mniejszy od 15 * 0.002 = 0.03, plus wymiana
> danych z php, ale trudno mi ocenić jaki jest jego narzut.
>

Wydaje mi się, że to co napisałeś nic nie da. Zwróć uwagę, że chce znaleźć
sąsiedni rekord ale taki, w którym a kolumnie ABC będą jakieś dane.
W praktyce udało mi się jakoś obejść problem uwzględniając pewne
statystyczne zależności w mojej tabeli.
W 99% przypadków poszukiwany rekord znajduje się bardzo blisko danego
rekordu (np. o wartości 30000).
Zapytanie SELECT MAX(Id) WHERE Id<30000 AND Id>29950 AND ABC!='NULL'
wykonuje się kilka tysięcy razy szybciej niż:
SELECT MAX(Id) WHERE Id<30000 AND AND ABC!='NULL'
Zupełnie mnie zaskoczyło, że na czas wykonywania zapytania do bazy MySQL ma
duży wpływ czas w jakim wykonywało się poprzednie zapytanie.

Paweł




Grzegorz Danowski - 13-11-2006 00:46

  Użytkownik "Paweł" <pawel.neo@neostrada.pl> napisał w wiadomości
news:ehtc3l$pji$1@atlantis.news.tpi.pl...
>
>> Jak Ci się uda zaimplementować, to podziel się wynikami na grupie. Wg
>> mojej
>> oceny, dla 30 tys. rekordów wykona się nie więcej niż 15 przebiegów
>> pętli, czyli czas całkowity będzie mniejszy od 15 * 0.002 = 0.03, plus
>> wymiana danych z php, ale trudno mi ocenić jaki jest jego narzut.
>>
>
> Wydaje mi się, że to co napisałeś nic nie da. Zwróć uwagę, że chce znaleźć
> sąsiedni rekord ale taki, w którym a kolumnie ABC będą jakieś dane.

Hmm, a co to ma do rzeczy, wystarczy przecież drobna modyfikacja:

record = Select Id From 'Tabela' Where Id < currId
And Id >= myValue AND ABC!='NULL' Limit 0, 1

A prawidła statystyczne mógłbyś wykorzystać zachowując dalej algorytm
wyszukiwania binarnego przez startowanie z punktu 0,99 razy szukana wartość,
trzeba byłoby jednak zmodyfikować sposób znajdowania kolejnego punktu (bo
nie można byłoby korzystać z step = step / 2).

Ale fajnie, że udało Ci się znaleźć lepszy sposób.

Pozdrawiam
Grzegorz




Paweł - 13-11-2006 00:46

  >> Wydaje mi się, że to co napisałeś nic nie da. Zwróć uwagę, że chce
>> znaleźć sąsiedni rekord ale taki, w którym a kolumnie ABC będą jakieś
>> dane.
>
> Hmm, a co to ma do rzeczy, wystarczy przecież drobna modyfikacja:
>
> record = Select Id From 'Tabela' Where Id < currId
> And Id >= myValue AND ABC!='NULL' Limit 0, 1
>
Faktycznie masz rację. Chyba sprawdzę w praktyce ten algorytm.

Paweł
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • effulla.pev.pl
  • comp
    [ms sql] =?ISO-8859-2?Q?wy=B6wietlenie_pierwszych_5_rekord?==?ISO-8859-2?Q?=F3w_z_zapytania_=3F_odpowiednik_ROWNUM_w_o?== ?ISO-8859-2?Q?raclu_dla_MS_SQL=27a?= [MySQL] =?ISO-8859-2?Q?Wy=B6wietlenie_kolejnej_pozycji=2C_?==?ISO-8859-2?Q?jak=B1_mia=B3by_dany_rekord=2C_gdybym_czyta=B3 _?==?ISO-8859-2?Q?wg_konkretnych_kryteri=F3w=2E_Da_si=EA_=3F?= Jak =?ISO-8859-2?Q?zamieni=E6_dwa_pola_jednej_kolumny_?==?ISO-8859-2?Q?w_dw=F3ch_rekordach_za_pomoc=B1_jednego_zapyt? ==?ISO-8859-2?Q?ania=3F?= [mysql/php] jak =?ISO-8859-2?Q?zliczy=E6_ilo=B6=E6_unikalnyc?==?ISO-8859-2?Q?h_rekord=F3w_w_jednym_zapytaniu=3F?= =?ISO-8859-2?Q?WY=B6wietlenie_rekord=F3w_pocz=B1wszy_od_?==?I SO-8859-2?Q?danej_litery=2E=2E=2E?= =?iso-8859-2?Q?=5BMySQL=5D_Wy=B6wietlenie_wszystkich_rekordow _zawierajacy?==?iso-8859-2?Q?ch_duplikat_a__moze_inna_struktura_bazy_danych ?= [pgsql] Akcja w =?iso-8859-2?b?emFsZb9ub7ZjaQ==?= od liczby zmienionych =?iso-8859-1?q?rekord=F3w?= [postgresql] kilka =?ISO-8859-2?Q?rekord=F3w_subquery_jako_?==?ISO-8859-2?Q?string?= [mysql] Wyszukanie =?ISO-8859-2?Q?rekord=F3w=28powiazane_tabel?==?ISO-8859-2?Q?e=29?= [MySQL]: Dodanie zliczania =?ISO-8859-2?Q?rekord=F3w_do_rozb?==?ISO-8859-2?Q?udowanego_zapytania?=
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • melooonka.opx.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