![]() |
![]() |
![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 728 Pomógł: 76 Dołączył: 12.06.2009 Ostrzeżenie: (0%) ![]() ![]() |
Mam takie proste zapytanie, którym pobieram określoną ilość rekordów i wszystko byłoby ok gdy w tabeli pola id występują stale po sobie czyli np. 1,2,3,4,5 itd. Lekki problem jest gdy tabela ma taką strukturę id 1,2,3,11,12,13 wtedy skrypt dla wartości $min = 4 i $max = 5 wykona pusty przebieg.
Próbowałem to rozwiązać wczytując w pętli id do tablicy, tylko to jest nieefektywne, nieeleganckie i w ogóle be. Może jest jakaś inna metoda, może być też inne zapytanie byleby pobierało rekordy z jakiegoś przedziału.
|
|
|
![]() |
![]()
Post
#2
|
|
Grupa: Moderatorzy Postów: 36 557 Pomógł: 6315 Dołączył: 27.12.2004 ![]() |
|
|
|
![]()
Post
#3
|
|
Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Czyli pole ID jest tekstem a nie numerem (czyli tak jak być powinno). Zmień to.
Przeszukiwanie rekordów zapytaniem operatorem beetween na głównym kluczu tabeli jest bardzo szybkie więc o "puste" przebiegi się nie martw. @nospor pamiętaj, żę beetween jest tu lepsze (IMG:style_emoticons/default/biggrin.gif)
Powód edycji: [wookieb]:
|
|
|
![]()
Post
#4
|
|
Grupa: Moderatorzy Postów: 36 557 Pomógł: 6315 Dołączył: 27.12.2004 ![]() |
Cytat pamiętaj, żę beetween jest tu lepsze ta, szczegolnie gdy trafi na luke....(IMG:style_emoticons/default/tongue.gif) Przeczytaj jeszcze raz dokladnie o co chodzi (IMG:style_emoticons/default/smile.gif) |
|
|
![]()
Post
#5
|
|
Grupa: Moderatorzy Postów: 8 989 Pomógł: 1550 Dołączył: 8.08.2008 Skąd: Słupsk/Gdańsk ![]() |
Czytam (IMG:style_emoticons/default/smile.gif) I biorę poprawkę na to, że autor tematu chyba nie do końca rozumie znaczenie operatora "BETWEEN" (IMG:style_emoticons/default/smile.gif)
|
|
|
![]()
Post
#6
|
|
Grupa: Moderatorzy Postów: 36 557 Pomógł: 6315 Dołączył: 27.12.2004 ![]() |
ALeż rozumie. I właśnie dlatego zadał pytanie na forum jak to inaczej napisac, bo gdy są luki to beetwen bedzie o kant 4 liter przy tym co on chce osiągnąć. I ja mu podałem alternatywę
|
|
|
![]()
Post
#7
|
|
Grupa: Zarejestrowani Postów: 728 Pomógł: 76 Dołączył: 12.06.2009 Ostrzeżenie: (0%) ![]() ![]() |
Tego chyba się jednak nie da rozwiązać tak jak tego oczekuje ale dzięki za odpowiedzi i poświęcony czas. Skrypt odczytuje z bazy danych limity $max i $min przy czym uruchamiany jest z CRON co 1 minutę.
wookieb - nie przejmuję się obciążeniem tylko jałowymi uruchomieniami, bo program mając np. różnicę 1000 pomiędzy numerami id czyli 100,101,102,1000,1001,1002 uruchomi się 1000 razy niepotrzebnie. Ale LIMIT tu nic nie zmienia bo program odczyta z bazy wartość pierwszą wstawi w $min, później obliczy $max na podstawie tego ale to NIE WYKLUCZA, że pomiędzy tymi wartościami nie będzie rekordów. |
|
|
![]()
Post
#8
|
|
Grupa: Moderatorzy Postów: 36 557 Pomógł: 6315 Dołączył: 27.12.2004 ![]() |
Cytat Ale LIMIT tu nic nie zmienia bo program odczyta z bazy wartość pierwszą wstawi w $min, później obliczy $max na podstawie tego ale to NIE WYKLUCZA, że pomiędzy tymi wartościami nie będzie rekordów. order by oraz limit dziala na zestawie danych nie zależnie czy są miedzy nimi dziury czy nie wiec naprawde nie wiem w czym masz teraz problem.
|
|
|
![]()
Post
#9
|
|
Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
A ja bym zapytał skąd Ty bierzesz $min i $max. Może sie bowiem okazać, że wyliczasz te dane niepotrzebnie, a istnieje zupełnie inne, prostsze podejście do rozwiązania. Nie wiem co konkretnie chcesz uzyskać, ale moim zdaniem niegłupi pomysł to zrobić zamiast jednego - dwa zapytania.
1) Uzyskaj z bazy liczbę rekordów spełniających zależność x >= $min AND x <= $max, z użyciem count() 2) jeśli uzyskany_wynik > 0 to zrób zapytanie SELECT (...) WHERE x >= $min ORDER BY x ASC LIMIT uzyskany_wynik Takie rozwiązanie, mimo iż pozornie wolniejsze może być szybkie i tylko na poziomie bazy jeśli zrobisz procedurę, do której jako paramtery prześlesz $min i $max. Count na indeksowanym polu będzie bardzo szybki i całość będzie kompletnie niewrażliwa na luki pomiędzy identyfikatorami. Jeszcze innym rozwiązaniem jest pobranie identyfikatorów rekordów spełniających warunek i tylko dla nich wykonać operację. Zwyczajnie opis szerzej problem, a może znajdzie się lepsze rozwiązanie problemu niż to co jest akurat w Twojej głowie i tak jak Ty byś tochciał rozwiązać. |
|
|
![]()
Post
#10
|
|
Grupa: Zarejestrowani Postów: 728 Pomógł: 76 Dołączył: 12.06.2009 Ostrzeżenie: (0%) ![]() ![]() |
order by oraz limit dziala na zestawie danych nie zależnie czy są miedzy nimi dziury czy nie wiec naprawde nie wiem w czym masz teraz problem. W tym mam problem, że skrypt się i tak uruchomi na pustym zestawie bo takie są odczytywane wartości z bazy danych. Żeby to działało tak jak chce to musiałbym zmodyfikować zapisywanie wartości w bazie dla $min i $max a nie wiem jak to zrobić czyli jaki warunek dać w linii EPIC FAIL. Zresztą tak wygląda fragment kodu za to odpowiedzialny. Program przy każdym uruchomieniu robi:
|
|
|
![]()
Post
#11
|
|
Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
Po pierwsze to optymalizuj sobie. Skoro z bazy pobierasz s($var) jakieś ustawienie konfiguracyjne, to po co w zapytaniu każesz my wypluć do dalszej obróbki całą tabelę? Nie prościej będzie w WHERE nazwę ustawienia konfiguracyjnego pchnąć?
inna sprawa... funkcja s('katalog') zwraca w chwili obecnej 579, a więc $katalog_limit_max = min(id) + 579; a więc minimum 579 a nie 5... Nie wiem gdzie te 5 widzisz. Nie widzę sensu tej operacji. Dla mnie w chwili obecnej cały mechanizm jaki zrobiłeś wygląda jak jakaś dziwna implementacja AUTO_INCREMENT dla kolumny z licznikiem katalogów... Napisz CO ma w zamiarach ten mechanizm robić. O co chodzi ze zmienną 'katalog' w ustawieniach. W chwili obecnej mam wrażenie, że przechowujesz liczbę dodanych katalogów w niej, ponieważ przy każdym uruchomieniu skryptu inkrementujesz go o liczbę s('pula'), czyli 1. Dla mnie ten kod jest jakiś "dziki" (IMG:style_emoticons/default/winksmiley.jpg) Naprawdę... Napisz co masz na wejściu, co mniej więcej ma kod zrobić i co ma dostać na wyjściu. Najlepiej w krokach i 2-3 krotnie, byśmy wiedzieli jak w "debugu" Twoich myśli zmienna katalog z settings miała by działać. Inaczej nie dojdziemy do zrozumienia pełnego co Twój kod ma tak naprawdę robić. |
|
|
![]()
Post
#12
|
|
Grupa: Zarejestrowani Postów: 728 Pomógł: 76 Dołączył: 12.06.2009 Ostrzeżenie: (0%) ![]() ![]() |
sorki tam zostały stare komentarze chciałem edytować ale wyskoczyło jakieś formatowanie html
OK zatem: na wejściu pobieram: - przesunięcie w katalog za pomocą s('katalog') jest to przesunięcie w tabeli katalogów liczone za pomocą pobrania minimalnej wartości id i dodania do niego zmiennej pobranej z bazy czyli s('katalog') która jest inkremantowana za każdym uruchomieniem programu o wartość s('pula'). - liczniki przesunięcia czyli s('pula') czyli ile katalogów ma za jednym uruchomieniem obsługiwać program, wartość tą można zmienić tylko z panelu admina i jak widać tutaj wynosi 1 Czyli jeśli uruchamiam program to program liczy $max w liniach 16-20 a $min = $max - s('pula') Następnie jest zapytanie:
|
|
|
![]()
Post
#13
|
|
Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
Jeśli więc dobrze rozumiem (nie mam pewności, więc jakby co mnie popraw), bierzesz sobie od startowego katalogu o min(id) ileś wpisów z bazy i obrabiasz je, po czym zapisujesz przesunięcie inkrementowane o pulę obrabianych. W następnym odpaleniu musisz obliczyć gdzie był zakończony cykl i od tego miejsca pracować dalej. Tak robisz aż do końca tabeli. Pytanie powstaje: "Czy ma sens taka implementacja przesunięcia?" Zauważ, że nie. Robisz masę niepotrzebnych obliczeń i odwołań do bazy w sytuacji gdzie nie jest to konieczne, ponieważ implementacja przesunięcia to u Ciebie lekko zakręcony algorytm, na dodatek problematyczny. Nieco źle podeszłeś do problemu, gdyż uparłeś się na taką, a nie inną realizację liczenia offsetu, który jest wrażliwy na dziury.
Wystarczy że podejdziesz do tego jak do paginacji. Tak naprawdę wystarczy gdy znasz pulę i numer kolejnego cyklu. Przebieg ma pulę 1 i tyle katalogów obrabia, ale zmieńmy to dla lepszej widoczności na 3. Rekordy w bazie mają dziury i wynoszą ich id: 1,2,3,4,6,7,9,12,15,16,17. Rusza cykl i bierze on pulę katalogów przesuniętą o numer cyklu przemnożony przez pulę. W bazie na chwilę obecna jest wartość cyklu czy tam katalogu = 0. Operacje się kończą inkrementujemy numer cyklu. Zauważ co się dzieje w kolejnych krokach by zauważyć ogromne uproszczenie całości Cykl 0: Pobranie 0*3, 3 czyli LIMIT 0, 3 -> rekordy 1,2,3 -> potem inkrementacja cyklu o 1 (do 1) Cykl 1: Pobranie 1*3, 3 czyli LIMIT 3, 3 -> rekordy 4,6,7 -> potem inkrementacja cyklu o 1 (do 2) Cykl 2: Pobranie 2*3, 3 czyli LIMIT 6, 3 -> rekordy 9,12,15 -> potem inkrementacja cyklu o 1 (do 3) Cykl 3: Pobranie 3*3, 3 czyli LIMIT 9, 3 -> rekordy 16,17 -> potem inkrementacja cyklu o 1 (do 4) Cykl 4: Pobranie 4*3, 3 czyli LIMIT 12, 3 -> BRAK rekordów wyniku, skrypt kończy działanie. Czy to nie o wiele prostsze rozwiązanie? Nie muszę znać min(id), nie muszę liczyć niczego tak naprawdę. Wystarczy że znam pulę, numer cyklu i nic więcej nie jest mi potrzebne do obliczenia wartości dla LIMIT. Masa niepotrzebnych zapytań do bazy oraz obliczeń "na boku" zredukowana do minimum niezbędnego |
|
|
![]()
Post
#14
|
|
Grupa: Zarejestrowani Postów: 1 590 Pomógł: 185 Dołączył: 19.04.2006 Skąd: Gdańsk Ostrzeżenie: (0%) ![]() ![]() |
Skoro problem dotyczy
Cytat i wszystko byłoby ok gdy w tabeli pola id występują stale po sobie czyli np. 1,2,3,4,5 to nie prościej ponumerować rekordy w bazie jednym szybkim zapytaniem przed tą operacją? Różnego rodzaju numerowanie często stosuje się w różnych rankingach czy zestawieniach, które z wiadomych powodów nie mogą być przeliczne w czasie rzeczywistym.
|
|
|
![]()
Post
#15
|
|
Grupa: Zarejestrowani Postów: 728 Pomógł: 76 Dołączył: 12.06.2009 Ostrzeżenie: (0%) ![]() ![]() |
thek tak skrypt powinien działać w ten sposób jaki opisujesz. Jednak LIMIT nie rozwiązuje tutaj problemu gdyż skrypt cały czas się uruchamia dla nie istniejących rekordów.
Ostatecznie skorzystałem z pomysłu Pilsener-a i takim zapytaniem zmodyfikowałem bazę tak żeby rekordy w id były po kolei ponumerowane i teraz jest już ok:
|
|
|
![]()
Post
#16
|
|
Grupa: Moderatorzy Postów: 4 362 Pomógł: 714 Dołączył: 12.02.2009 Skąd: Jak się położę tak leżę :D ![]() |
Ale jak się uruchamia dla nie istniejących rekordów? Widzisz by to robił? Pobieram za każdym razem tylko istniejące. LIMIT mi pobiera tylko kolejne po sobie rekordy... Skoro nakazuję mu pobrać 3, to nie robi mi luki w cyklu 1 gdzie mam 4,6,7 do postaci 4,6 co postulujesz jakoby robił. LIMIT pobiera kolejne pasujące do wzorca i NIE wstawia nie istniejących, w tym wypadku nie robi pustego przebiegu dla 5, ale pobiera brakujący mu dla 3 rekordów następny element, a więc o id =7... Chciałeś w zapytaniu kolejne 3 rekordy? Dostałeś 3, a nie 2. Chyba kompletnie nie rozumiesz jak działa LIMIT w MySQL. On nie robi sobie LIMIT X, Y jako pobierz od rekordu o id = X do rekordu o id = Y. LIMIT działa na zasadzie: pobierz od rekordu mającego indeks X spośród wybranych zapytaniem wyników kolejne Y rekordów. A to cholernie duża różnica.
Popatrz na wywołania. Czy dla cyklu 0 zaczyna mi od rekordu o id 0 czy od 1? a przecież mam LIMIT 0, 3 i patrz dalej... Dlaczego mi się "cudem" kompletnie liczby w LIMIT nie pokrywają z uzyskiwanymi jako wyniki? LIMIT 6, 3 daje rekordy 9,12,15, więc jak to wyjaśnisz? Jakoś nie daje od rekordu o id = 6 do 6+3, czyli id = 9 (IMG:style_emoticons/default/smile.gif) Samo zapytanie daje dobre rezultaty. Widocznie gdzieś inna część skryptu ma walniętą pętlę for($i = $min; $i < $min+$pula; $i++) i to ona Ci brudzi, a nie zapytanie. Lepiej posprawdzaj dokładnie, bo jak na razie to Twój opis działania LIMIT jest dla mnie herezją (IMG:style_emoticons/default/winksmiley.jpg) Gdy już ją znajdziesz zamień ją na foreach lub while i dopiero wtedy sprawdź czy wszystko jest cacy. Bo jak dla mnie tak masz najpewniej zrobione i szukasz byka w logice nie tam gdzie on faktycznie jest. |
|
|
![]()
Post
#17
|
|
Grupa: Zarejestrowani Postów: 1 590 Pomógł: 185 Dołączył: 19.04.2006 Skąd: Gdańsk Ostrzeżenie: (0%) ![]() ![]() |
Możesz ponumerować rekordy jednym zapytaniem używając zmiennej: http://nospor.pl/mysql-faq.html#faq-6
|
|
|
![]() ![]() |
![]() |
Aktualny czas: 23.08.2025 - 23:39 |