Optymalizacja zapytań do następnego i poprzedniego elementu

głosy
28

Szukam najlepszego sposobu, aby pobrać następny i poprzednie rekordy rekordu bez uruchamiania pełnej kwerendy. Mam w pełni wdrożone rozwiązanie w miejscu, a chcieliby wiedzieć, czy są jakieś lepsze sposoby, aby to zrobić tam.

Powiedzmy budujemy stronę internetową dla fikcyjnej Warzywniak. W uzupełnieniu do swoich stron HTML, co tydzień, chce opublikować listę ofert specjalnych na swoim miejscu. Chce te oferty do przebywania w rzeczywistej tabeli bazy danych, a użytkownicy muszą mieć możliwość sortowania ofert na trzy sposoby.

Każdy element musi również mieć stronę z większą ilością szczegółów, informacji tekstowych o ofercie i „Poprzedni” i „Next” przycisków. „Poprzedniej” i „Dalej”, przyciski muszą wskazywać na sąsiednich wpisów w zależności od sortowania użytkownik wybrał na liście .

alt text http://www.pekkagaiser.com/stuff/Sort.gif?

Oczywiście, „next” przycisk „pomidory, klasa I” musi być „Jabłka, klasa 1” w pierwszym przykładzie „gruszki, klasa I” w sekundę, a żaden w trzecim.

Zadanie w widoku szczegółów jest do określenia następnego i poprzednie pozycje bez uruchamiania kwerendy za każdym razem , z porządkiem sortowania listy jako jedynej dostępnej informacji (powiedzmy mamy, że za pośrednictwem parametru GET ?sort=offeroftheweek_price, a ignorować wpływ na bezpieczeństwo) ,

Oczywiście, po prostu przekazując identyfikatory następnych i poprzednich elementów jako parametr jest pierwszym rozwiązaniem, które przychodzi do głowy. Po tym wszystkim, wiemy już identyfikator Jest w tym momencie. Ale to nie jest opcją tutaj - będzie pracować w tym uproszczonym przykładzie, ale nie w wielu moich przypadków użycia świata rzeczywistego.

Moje obecne podejście w moim CMS używa coś mam nazwie „sortowania pamięci podręcznej”. Gdy lista jest załadowany, przechowywać położenia elementu w ewidencji w tabeli o nazwie sortingcache.

name (VARCHAR)             items (TEXT)

offeroftheweek_unsorted    Lettuce; Tomatoes; Apples I; Apples II; Pears
offeroftheweek_price       Tomatoes;Pears;Apples I; Apples II; Lettuce
offeroftheweek_class_asc   Apples II;Lettuce;Apples;Pears;Tomatoes

Oczywiste jest, że itemskolumna jest naprawdę wypełnione identyfikatorów numerycznych.

Na stronie szczegółów, mam teraz dostępu do odpowiedniego sortingcacherekordu pobrać itemskolumnę, eksplodować go szukać aktualnej pozycji ID i powrócić do poprzedniego i następnego sąsiada.

array(current   => Tomatoes,
      next      => Pears,
      previous  => null
      );

Jest to oczywiście kosztowne, pracuje dla ograniczonej liczby tylko rekordy i tworzy nadmiarowe dane, ale załóżmy, że w realnym świecie, zapytanie do tworzenia list jest bardzo drogie (to jest), uruchomienie go w każdym szczególe widzenia jest z pytanie, a niektóre potrzebna jest buforowanie.

Moje pytania:

  • Czy uważasz, że jest to dobra praktyka, aby dowiedzieć się rekordy sąsiadującymi różnym rozkazy zapytań?

  • Czy wiesz lepszych praktyk w zakresie wydajności i prostoty? Czy coś, co sprawia, że ​​ten całkowicie przestarzały wiedzieć?

  • W teorii programowania, jest tam nazwa tego problemu?

  • Czy nazwa „Sortowanie cache” jest właściwe i zrozumiałe dla tej techniki?

  • Czy istnieją jakieś wspólne wzorce uznane, aby rozwiązać ten problem? Jak one się nazywają?

Uwaga: Moje pytanie nie jest o budowaniu listy, lub w jaki sposób wyświetlić widok szczegółów. Są to tylko przykłady. Moje pytanie jest podstawowe funkcje wyznaczania sąsiadów rekordu kiedy ponowne zapytanie jest niemożliwe, a najszybszy i najtańszy sposób, aby się tam dostać.

Jeśli coś jest niejasne, proszę zostawić komentarz i będę wyjaśnić.

Począwszy bounty - może tam jest trochę więcej informacji na ten temat tam.

Utwórz 22/02/2010 o 12:06
źródło użytkownik
W innych językach...                            


11 odpowiedzi

głosy
-3

Więc masz dwa zadania:

  1. budować posortowaną listę elementów (wybór z różnych ORDER BY)
  2. Wyświetl informacje o każdej pozycji (Wybierz dane z bazy danych z możliwością buforowania).

Jaki jest problem?

PS: jeśli zamówiono lista może być zbyt duża, wystarczy funkcjonalność PAGER realizowane. Nie może być różne implementacje, np może chcesz dodać „limit 5” na zapytania i dostarczyć „Pokaż przycisk” Next 5. Po naciśnięciu tego przycisku, stan jak „GDZIE cena <0,89 LIMIT 5” dodaje.

Odpowiedział 22/02/2010 o 15:04
źródło użytkownik

głosy
16

Oto pomysł. można odciążyć kosztownych operacji do aktualizacji, gdy wkładki Grocer / aktualizuje nowych ofert aniżeli kiedy użytkownik końcowy wybiera dane do widoku. To może wydawać się bez dynamiczny sposób, aby obsłużyć dane sortowania, ale może zwiększyć prędkość. A, jak wiadomo, zawsze jest kompromis między wydajnością i innych czynników kodowania.

Utwórz tabelę do przechowywania następny i poprzedni dla każdej oferty i każdej opcji sortowania. (Alternatywnie, można zapisać to w tabeli, jeśli oferta będzie zawsze masz trzy opcje sortowania - prędkość zapytanie jest dobry powód, aby denormalize bazy danych)

Więc masz te kolumny:

  • Sortuj Type (nieposortowane, cena, klasa i cena opis produktu)
  • oferta ID
  • Poprzedni ID
  • Następny ID

Gdy informacja szczegółów na stronie oferta szczegół jest pytani z bazy danych, NextID i PrevID byłaby część wyników. Więc trzeba tylko jedno zapytanie dla każdej strony szczegółów.

Za każdym razem oferta jest włożona, zaktualizowane lub usunięte, trzeba by uruchomić proces, który sprawdza integralność / dokładność tabeli sorttype.

Odpowiedział 22/02/2010 o 20:20
źródło użytkownik

głosy
1

Nie jestem pewien, czy zrozumiałem dobrze, więc jeśli nie, to po prostu powiedz mi;)

Powiedzmy, że Givens są zapytania do posortowanej listy i prądu przesunięcia na tej liście, to znaczy mamy $queryi $n.

Bardzo oczywiste rozwiązanie w celu zminimalizowania zapytań byłoby pobrać wszystkie dane na raz:

list($prev, $current, $next) = DB::q($query . ' LIMIT ?i, 3', $n - 1)->fetchAll(PDO::FETCH_NUM);

To stwierdzenie pobiera poprzedni, bieżący i następny elementów z bazy danych w bieżącym porządku sortowania i stawia powiązanych informacji do odpowiednich zmiennych.

Ale jak to rozwiązanie jest zbyt proste, zakładam, że coś źle.

Odpowiedział 07/02/2011 o 20:31
źródło użytkownik

głosy
2

Miałem koszmary z tego jak dobrze. Twoje obecne podejście wydaje się być najlepszym rozwiązaniem nawet dla list 10k przedmiotów. Buforowanie identyfikatory widoku listy w sesji HTTP i następnie przy użyciu, że do wyświetlania (personalizowany do bieżącego użytkownika) poprzedni / następny. Działa to dobrze zwłaszcza, gdy istnieje zbyt wiele sposobów filtrowania i sortowania wstępną listę elementów, a nie tylko 3.
Ponadto, przechowując całą listę identyfikatorów można dostać się do wyświetlania "you are at X out of Y"użyteczność zwiększenie tekstu.
JIRA na poprzedni / następny

Nawiasem mówiąc, to co JIRA robi, jak również.

Aby bezpośrednio odpowiedzieć na Twoje pytania:

  • Tak to jest dobra praktyka, ponieważ waga to bez dodatkowej złożoności kodu, gdy filtr / sortowanie i typy elementów piać bardziej skomplikowane. Używam go w systemie produkcyjnym z 250k artykułów z „nieskończonych” Wariacje filtr / sortowanie. Przycinanie Cacheable identyfikatorów 1000 jest również możliwość ponieważ użytkownik nigdy nie będzie najprawdopodobniej kliknij prev lub następny ponad 500 razy (będzie on najprawdopodobniej wrócić i uściślić wyszukiwanie lub paginate).
  • Nie znam lepszego sposobu. Ale jeśli sortuje gdzie ograniczona i to było miejsce publiczne (bez sesji HTTP) wtedy bym najprawdopodobniej denormalize.
  • Nie wiem.
  • Tak, sortowanie cache brzmi dobrze. W moim projekcie I nazywają to „poprzednia / następna strona w wynikach wyszukiwania” lub „Nawigacja w wynikach wyszukiwania”.
  • Nie wiem.
Odpowiedział 07/02/2011 o 21:04
źródło użytkownik

głosy
2

W ogóle denormalize dane z indeksami. Mogą one być przechowywane w tych samych wierszach, ale prawie zawsze odzyskać swoje identyfikatory rezultacie, następnie zrobić oddzielną wycieczkę do danych. To sprawia, buforowanie danych bardzo proste. To nie jest tak ważne w PHP gdzie opóźnienie jest niska, a pasmo wysokie, ale taka strategia jest bardzo przydatna, gdy masz duże opóźnienia, niski aplikację przepustowości, takich jak strony AJAX gdzie wiele z witryny jest renderowane w JavaScript.

I zawsze buforować listy wyników, a same wyniki osobno. Jeśli coś wpływa na wyniki kwerendy listy, pamięć podręczna wyników lista jest odświeżana. Jeśli coś wpływa na wyniki siebie, szczególnie te wyniki są odświeżane. To pozwala mi aktualizować ani jednego bez konieczności regeneracji wszystkiego, co skutkuje skutecznym buforowania.

Ponieważ moje listy wyników rzadko się zmieniają, wygenerować wszystkie listy w tym samym czasie. Może to sprawić, że początkowa reakcja nieco wolniej, ale upraszcza cache orzeźwiający (wszystkie listy przechowywane w jednym wejściu cache).

Bo mam całą listę pamięci podręcznej, to jest trywialne, aby znaleźć sąsiednie elementy bez revisiting bazy danych. Przy odrobinie szczęścia, dane dotyczące tych elementów będzie również buforowane. Jest to szczególnie przydatne podczas sortowania danych w języku JavaScript. Jeśli mam już kopię pamięci podręcznej po stronie klienta, czy mogę odwołać się od razu.

Aby odpowiedzieć na Twoje pytania szczególności:

  • Tak, jest to fantastyczny pomysł, aby dowiedzieć się, że sąsiedzi z wyprzedzeniem, czy cokolwiek informacji klient może przejść obok, zwłaszcza jeśli koszt jest niski koszt i teraz przeliczyć jest wysoka. Wtedy to po prostu kompromis z dodatkowym wstępnej kalkulacji i przechowywania kontra prędkością.
  • Pod względem wydajności i prostoty, unikać muchowe rzeczy razem, które są logicznie różne rzeczy. Indeksy i dane są różne, mogą być zmienione w różnych momentach (np dodanie nowego punktu odniesienia wpłynie na indeksy, ale nie istniejące dane), a zatem powinny być dostępne oddzielnie. To może być nieco mniej efektywne z punktu widzenia jednowątkowy, ale za każdym razem, gdy coś związać razem tracisz buforowanie skuteczności i asychronosity (klucz do skalowania jest asychronosity).
  • Termin do pobierania danych z wyprzedzeniem jest pre-ściągam. Pre-ściągam mogą się zdarzyć w czasie dostępu lub w tle, ale zanim dane wstępnie naciągane jest rzeczywiście potrzebne. Podobnie ze wstępnym obliczeniu. Jest to kompromis kosztu teraz, koszty magazynowania i koszty, aby uzyskać w razie potrzeby.
  • „Sortowanie cache” jest apt nazwa.
  • Nie wiem

Również podczas buforowania rzeczy, buforować je w najbardziej możliwym poziomie rodzajowego. Niektóre rzeczy mogą być specyficzne użytkownika (takich jak wyniki wyszukiwania dla zapytania), gdzie inni mogą być niezależne od użytkownika, takich jak przeglądanie katalogu. Oba mogą korzystać z pamięci podręcznej. Zapytanie Katalog może być częste i zaoszczędzić trochę za każdym razem, a zapytanie wyszukiwania mogą być kosztowne i zaoszczędzić kilka razy.

Odpowiedział 09/02/2011 o 08:00
źródło użytkownik

głosy
0

Istnieje wiele sposobów na to, aby skóra przysłowiowy kot. Więc oto kilka moich.

Jeśli oryginalny zapytanie jest drogie, co można powiedzieć to, a następnie utworzyć inną tabelę ewentualnie tablicę pamięci wypełniania go z wynikami Twój drogie i rzadko uruchomić główny zapytania.

Ta druga tabela może następnie być sprawdzony na każdym widoku i sortowania jest tak proste, jak ustawienie odpowiedniego porządek.

Gdy nie jest wymagana repopulate drugą tablicę z wynikami pierwszej tabeli, utrzymując w ten sposób dane świeże, ale minimalizuje stosowanie kosztownego zapytania.

Alternatywnie, jeśli chcesz uniknąć nawet podłączenia do db następnie można przechowywać wszystkie dane w tablicy PHP i przechowywać go za pomocą memcached. byłoby to bardzo szybko i pod warunkiem, twoje listy nie były zbyt wielka byłaby zasobooszczędną. i mogą być łatwo posortowane.

DC

Odpowiedział 11/02/2011 o 05:19
źródło użytkownik

głosy
0

Podstawowe założenia:

  • Specjały są raz w tygodniu
  • Możemy oczekiwać, aby zmienić miejsce rzadko ... prawdopodobnie codziennie?
  • Możemy kontrolować aktualizacje bazy danych z eteru API lub reagować poprzez wyzwalacze

Jeśli witryna zmienia się codziennie, sugeruję, że wszystkie strony są generowane statycznie przez noc. Jedno zapytanie dla każdego porządek_sortowania iteracji i sprawia, że ​​wszystkie związane stron. Nawet jeśli istnieją elementy dynamiczne, na to, że można je rozwiązać poprzez włączenie statyczne elementy strony. To zapewni optymalną obsługę strony i bez obciążenia bazy danych. W rzeczywistości, można ewentualnie generować oddzielne strony i prev / kolejne elementy, które znajdują się na stronach. Może to być szalony 200 sposobów sortowania, ale z 3 Jestem wielkim fanem tego.

?sort=price
include(/sorts/$sort/tomatoes_class_1)
/*tomatoes_class_1 is probably a numeric id; sanitize your sort key... use numerics?*/

Jeśli z jakiegoś powodu nie jest to możliwe, chciałbym odwołać się do zapamiętywania. Memcache jest popularny do tego typu rzeczy (pun!). Kiedy coś jest popychany do bazy danych, można wydać spust zaktualizować pamięć podręczną z prawidłowymi wartościami. Zrobić to w taki sam sposób, jeśli byłoby tak, jakby istniała Zaktualizowana pozycja w 3 połączonych list - ponownie połączyć odpowiednio (this.next.prev = this.prev, etc). Od tego, jak długo, jak nie przepełnić bufor, będziesz pociągając prosto z pamięci wartości klucza podstawowego w modzie.

Metoda ta zajmie trochę dodatkowego kodowania na wybranych i aktualizacja / Wstaw metod, ale powinno być raczej minimalne. W końcu będziesz patrząc w górę [id of tomatoes class 1].price.next. Jeśli ten klucz jest w pamięci podręcznej, złoty. Jeśli nie, wstawić do pamięci podręcznej i wyświetlacz.

  • Czy uważasz, że jest to dobra praktyka, aby dowiedzieć się rekordy sąsiadującymi różnym rozkazy zapytań? Tak. Dobrze jest wykonać przeglądowej aheads oczekiwanych nadchodzących żądań.
  • Czy wiesz lepszych praktyk w zakresie wydajności i prostoty? Czy coś, co sprawia, że ten całkowicie przestarzały wiedzieć? Mam nadzieję, że powyższe
  • W teorii programowania, jest tam nazwa tego problemu? Optymalizacja?
  • Czy nazwa „Sortowanie cache” jest właściwe i zrozumiałe dla tej techniki? Nie jestem pewien konkretnego odpowiedniej nazwy. Jest buforowanie, jest to swego rodzaju bufor, ale nie jestem pewien, że mówi do mnie masz „Sortowanie cache” byłoby przekazać natychmiastowe zrozumienie.
  • Czy istnieją jakieś wspólne wzorce uznane, aby rozwiązać ten problem? Jak one się nazywają? Buforowanie?

Niestety moje odpowiedzi osadowych są trochę bezużyteczny, ale myślę, że moje rozwiązania narracyjne powinno być całkiem przydatne.

Odpowiedział 11/02/2011 o 18:13
źródło użytkownik

głosy
0

Można zapisać numery wierszy zamawianego list do poglądów , i można dotrzeć do poprzedniej i następnej pozycji na liście poniżej (current_rownum + 1) Numery wierszy (current_rownum-1) i.

Odpowiedział 12/02/2011 o 14:01
źródło użytkownik

głosy
0

Problem / datastructur nazwie dwukierunkowy wykres czy można powiedzieć, że masz kilka połączonych list.

Jeśli myślisz o tym, jak połączonej listy, można po prostu dodać pola do tabeli elementów za każdym sortowaniu i prev / następnej klucza. Ale osoba DB zabije cię za to, to jak Goto.

Jeśli uważasz, że jest to (bi) kierunkową wykresie, idziesz z odpowiedzią Jessiki. Głównym problemem jest, że aktualizacje rzędu są kosztowne operacje.

 Item Next Prev
   A   B     -
   B   C     A
   C   D     B
   ...

Jeżeli zmienisz pozycję jeden rzeczy do nowego porządku A, C, B, D, trzeba będzie zaktualizować 4 wiersze.

Odpowiedział 13/02/2011 o 02:20
źródło użytkownik

głosy
4

Mam pomysł, nieco podobny do Jessiki. Jednak zamiast zapisywania linków do następnych i poprzednich punktach sortowanie, przechowywanie porządek sortowania dla każdego rodzaju sortowania. Aby znaleźć poprzednią lub następną płytę, po prostu wiersz z SortX = currentSort ++ lub SortX = currentSort--.

Przykład:

Type     Class Price Sort1  Sort2 Sort3
Lettuce  2     0.89  0      4     0
Tomatoes 1     1.50  1      0     4
Apples   1     1.10  2      2     2
Apples   2     0.95  3      3     1
Pears    1     1.25  4      1     3

Takie rozwiązanie dałoby bardzo krótkie czasy zapytań i zajmie mniej miejsca na dysku niż pomysł Jessiki. Jednak, jak jestem pewien, że zdajesz sobie sprawę, koszt aktualizacji jeden wiersz danych jest znacznie wyższe, ponieważ trzeba przeliczyć i przechowywania wszystkich zleceń sortowania. Ale nadal, w zależności od sytuacji, jeśli aktualizacje danych są rzadkie, a zwłaszcza jeśli zawsze zdarzają się w dużych ilościach, to rozwiązanie może być najlepszym.

to znaczy

once_per_day
  add/delete/update all records
  recalculate sort orders

Nadzieję, że to jest przydatne.

Odpowiedział 13/02/2011 o 03:30
źródło użytkownik

głosy
0

Przeprosiny czy mam źle, ale myślę, że chcesz zachować uporządkowaną listę pomiędzy użytkownik uzyskuje dostęp do serwera. Jeśli tak, to odpowiedź może również leżeć w swojej strategii i technologii buforowania niż w optymalizacji zapytań bazy danych / schematu.

Moje podejście byłoby serializacji () tablicę raz pierwszy jej pobraniu, a następnie, że w pamięci podręcznej do oddzielnego obszaru pamięci; czy to memcached / APC / twardego dysku / MongoDB / itd. i zachowuje swoje dane lokalizacji cache dla każdego użytkownika indywidualnie przez swoich danych sesyjnych. Rzeczywista backend składowania będzie naturalnie być uzależniona od wielkości tablicy, która nie idź na wiele szczegółów na temat, ale memcached wielka skale nad wieloma serwerami i Mongo jeszcze w nieco większym kosztem utajenia.

Ty również nie wskazują, ile porządek permutacji istnieją w świecie rzeczywistym; np zrobić trzeba buforować oddzielne listy na użytkownika, można też globalnie cache za sortowania permutacji a następnie odfiltrować co nie trzeba za pośrednictwem PHP ?. Na przykład dajesz, bym po prostu buforować obie permutacje i sklep, który z nich musiałem unserialize () w danych sesji.

Gdy użytkownik powraca do miejsca, sprawdzić czas życia wartość danych w pamięci podręcznej i ponowne wykorzystanie go jeśli nadal aktualne. Chciałbym również mieć spust działa na INSERT ignorowanie / UPDATE / DELETE dla ofert specjalnych, które po prostu ustawia pola datownika w osobnej tabeli. To od razu wskazać, czy cache był czerstwy i kwerenda musiała być ponownie prowadzony przez bardzo niski koszt zapytania. Wspaniałą rzeczą tylko za spust, aby ustawić pojedyncze pole jest to, że nie trzeba się martwić o przycinanie starych / wartości zwolnionych z tej tabeli.

Czy to jest odpowiedni będzie zależeć od rozmiaru danych są zwracane, jak często był on modyfikowany, a co buforowanie technologie są dostępne na serwerze.

Odpowiedział 13/02/2011 o 15:47
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more