Optimalizace dotazů pro další a předchozí prvek

hlasů
28

Já jsem hledal nejlepší způsob, jak načíst další a předchozí záznamy o záznamu, aniž by hrozilo úplné dotazu. Mám plně implementované řešení na místě, a chtěl bych vědět, jestli existují nějaké lepší přístupy, jak to udělat venku.

Řekněme, že jsme budování webové stránky pro fiktivní zelinář. Kromě svých HTML stránek, každý týden, chce zveřejnit seznam speciálních nabídek na jeho místě. Chce ty nabídky k pobytu ve skutečném tabulce databáze, a uživatelé musí mít možnost třídit nabídek třemi způsoby.

Každá položka má také mít detailní stránku s větší, textové informace o zakázce a tlačítek „předchozí“ a „další“. Dále jen „předchozí“ a „další“ tlačítka je třeba poukázat na sousedních položky v závislosti na třídění uživatel zvolil na seznamu .

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

Je zřejmé, že tlačítko „Další“ pro „Rajčata, Class I“ musí být „Jablka, třída 1“ v prvním příkladě, „hrušky, třída I“ ve druhém, a nemá v třetí.

Úkolem v detailním pohledu je určit další a předchozí položky, aniž by hrozilo pokaždé dotazu s pořadí řazení seznamu jako jediný dostupný informací (řekněme, dostaneme, že prostřednictvím parametru GET ?sort=offeroftheweek_pricea ignorovat bezpečnostní důsledky) ,

Je zřejmé, že prostě absolvování identifikátory další a předchozí prvky jako parametr je první řešení, které přijde na mysl. Koneckonců, už víme, IDs v tomto okamžiku. Ale to není zde možnost - to bude fungovat v tomto zjednodušeném příkladu, ale ne mnoho mých případů použití v reálném světě.

Můj současný přístup v mém CMS používá něco, co jsem s názvem „třídění vyrovnávací paměť“. Při načtení seznamu I ukládat položky pozice v záznamech v tabulce s názvem 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

Je zřejmé, že itemssloupec je skutečně naplněna číselných identifikátorů.

Na stránce s podrobnostmi, teď přistupovat příslušný sortingcachezáznam, načíst itemssloupec, explodovat to, hledat aktuální číslo položky a návrat na předchozí a následující souseda.

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

To je samozřejmě dražší, pracuje pro omezený počet pouze záznamy a vytváří redundantní data, ale předpokládejme, že v reálném světě, dotaz k vytváření seznamů je velmi drahé (je to), běží to v každém detailu je mimo otázkou, a některé je třeba cache.

Moje otázky:

  • Myslíte si, že je to dobré praxe zjistit sousední záznamy pro různé dotazu příkazy?

  • Víte, lepší postupy z hlediska výkonu a jednoduchosti? Víte něco, co dělá to naprosto zastaralé?

  • V teorii programování, je tam název pro tento problém?

  • Je název „Třídění cache“, je vhodné a srozumitelné pro tuto techniku?

  • Existují nějaké uznávané, běžné způsoby, jak vyřešit tento problém? Co říkali?

Poznámka: Moje otázka není o budování seznamu, nebo jak zobrazit detailní pohled. To jsou jen příklady. Moje otázka je základní funkce určování sousedy záznamu, když re-query je nemožné, a nejrychlejší a nejlevnější způsob, jak se tam dostat.

Pokud je něco nejasné, prosím zanechat komentář a budu objasnit.

Spuštění odměnu - možná je trochu více informací o této venku.

Položena 22/02/2010 v 12:06
zdroj uživatelem
V jiných jazycích...                            


11 odpovědí

hlasů
-3

Takže máte dva úkoly:

  1. stavět seřazený seznam položek (Vybírá s různou ORDER BY)
  2. zobrazit podrobnosti o každé položce (vyberte detaily z databáze s možností ukládání do mezipaměti).

Co je za problém?

PS: pokud seřazený seznam může být příliš velký, stačí funkce pager implementována. Tam by mohly být různé implementace, například budete chtít přidat „LIMIT 5“ do dotazu a poskytovat „Zobrazit další 5“ tlačítko. Při stisknutí tohoto tlačítka, stav jako „WHERE cena <0.89 LIMIT 5“ je přidán.

Odpovězeno 22/02/2010 v 15:04
zdroj uživatelem

hlasů
16

Tady je nápad. Dalo by se složit drahé operace na aktualizaci, když kupce vložky / aktualizuje nové nabídky, spíše než když koncový uživatel vybere data zobrazit. To se může zdát jako non-dynamický způsob, jak zvládnout data třídit, ale to může zvýšit rychlost. A jak víme, je vždy kompromis mezi výkonem a dalšími kódování faktorů.

Vytvořit tabulku držet další a předchozí pro každou nabídku a každé možnosti třídění. (Případně můžete uložit toto v zakázce tabulce, pokud budete mít vždy tři možnosti třídění - rychlost dotaz je dobrý důvod k denormalize databáze)

Takže byste mít tyto sloupce:

  • Typ řazení (Nezařazené, Cena, Class a Price Desc)
  • ID nabídky
  • Předchozí číslo
  • příští číslo

Je-li detailní informace o zakázce stránce s podrobnostmi dotazovaný z databáze, NextID a PrevID by být součástí výsledků. Takže budete potřebovat pouze jeden dotaz pro každou stránku podrobností.

Pokaždé, když nabídka je vložen, aktualizovány nebo odstraněny, budete muset spustit proces, který ověřuje integritu / přesnost tabulky sorttype.

Odpovězeno 22/02/2010 v 20:20
zdroj uživatelem

hlasů
1

Nejsem si jistý, jestli jsem to pochopil dobře, tak ne-li, řekni mi;)

Řekněme, že givens jsou dotaz na tříděný seznam a proudem offset v tomto seznamu, tedy máme $querya $n.

Velmi jasné řešení, aby se minimalizovalo dotazy, by se načíst všechna data najednou:

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

Toto tvrzení načte předchozí, současný a dalších prvků z databáze v aktuálním pořadí řazení a dá související informace do příslušných proměnných.

Ale jak je toto řešení příliš jednoduché, předpokládám, že špatně pochopil jsem něco.

Odpovězeno 07/02/2011 v 20:31
zdroj uživatelem

hlasů
2

Měl jsem noční můry s tímto jeden stejně. Váš současný přístup se zdá být nejlepším řešením i pro seznamy 10k bodů. Caching identifikátory zobrazení seznamu v relaci HTTP a pak pomocí že pro zobrazování (přizpůsobené pro aktuálního uživatele) předchozí / následující. To funguje dobře, zvláště když existuje příliš mnoho způsobů, jak filtrovat a třídit počáteční seznam položek, namísto pouhých 3.
Také uložením celý Seznam uživatelských jmen se dostanete k zobrazení "you are at X out of Y"textu použitelnosti zlepšení.
JIRA je předchozí / další

Mimochodem, to je to, co JIRA dělá stejně.

Chcete-li přímo zodpoví Vaše otázky:

  • Ano, je to dobré praxe, protože váhy bez jakékoli přidané složitosti kódu, pokud váš filtr / třídění typy položek vrána složitější. Já to za použití ve výrobním systému s 250K články s „nekonečným“ filtr / třídění variací. Ořezávání cacheable ID 1000 je také možnost, protože uživatel bude s největší pravděpodobností nikdy kliknout na prev nebo další více než 500 krát (Bude s největší pravděpodobností vrátit zpět a upřesnění vyhledávání nebo stránkování).
  • Nevím o lepším způsobem. Ale v případě, že druhy, kde omezené, a to byl veřejný pozemek (bez http relace), pak bych s největší pravděpodobností denormalize.
  • Nevím.
  • Ano, třídění mezipaměti zní dobře. V mém projektu jsem to nazval „předchozí / další ve výsledcích vyhledávání“ nebo „navigace ve výsledcích vyhledávání“.
  • Nevím.
Odpovězeno 07/02/2011 v 21:04
zdroj uživatelem

hlasů
2

Obecně platí, že denormalize data z indexů. Mohou být skladovány ve stejných řadách, ale téměř vždy získám můj výsledek ID, pak se samostatnou cestu pro data. To dělá cache dat velmi jednoduché. Není to v PHP tak důležité, kde je čekací doba je nízká a šířku pásma vysoká, ale taková strategie je velmi užitečné, když máte vysokou latencí, nízký aplikace šířku pásma, jako je například webové stránky AJAX, kde velká část areálu je vykreslen v JavaScriptu.

Vždycky jsem mezipaměti seznamy výsledků a samotné výsledky odděleně. Kdyby nic jiného ovlivňuje výsledky dotazu seznamu cache výsledků seznamu je svěží. Kdyby se něco ovlivní výsledky sami, tyto konkrétní výsledky jsou aktualizovány. To mi umožňuje aktualizovat buď jeden, aniž by museli obnovit vše, což má za následek efektivní ukládání do mezipaměti.

Vzhledem k tomu, moje seznamy výsledků zřídka mění, jsem generovat všechny seznamy najednou. To může mít za následek počáteční reakce o něco pomalejší, ale to zjednodušuje vyrovnávací osvěžující (všechny seznamy se ukládají do jednoho záznamu paměti cache).

Protože mám celý seznam mezipaměti, je to triviální najít sousední položky bez přehodnocení databázi. S trochou štěstí, bude také cache data pro tyto položky. To je zvláště užitečné při třídění dat v JavaScriptu. Když už mám kopii mezipaměti na straně klienta, mohu uchýlit okamžitě.

Chcete-li odpovědět na vaše otázky konkrétně:

  • Ano, je to skvělý nápad, aby zjistit sousedy dopředu, nebo jakékoli informace, že klient je pravděpodobné, že přístup k další, a to zejména v případě, že cena je nyní nízká a náklady na přepočítat je vysoká. Pak je to prostě kompromis extra pre-výpočtu a ukládání v závislosti na rychlosti.
  • Z hlediska výkonu a jednoduchosti se zabránilo vázání věci dohromady, které jsou logicky odlišné věci. Indexy a údaje jsou různé, které by mohly být změněny v různých časech (např přidání nový vztažný bod bude mít vliv na indexy, ale ne existující data), a proto by měly být přístupné pouze samostatně. To může být o něco méně efektivní z jednovláknové hlediska, ale pokaždé, když tie něco společně, můžete přijít do mezipaměti účinnost a asychronosity (klíčem k měřítka je asychronosity).
  • Termín pro získávání dat dopředu je pre-okouzlující. Pre-načítání se může stát v době přístupu nebo v pozadí, ale předtím, než je ve skutečnosti potřeba předběžně načtené údaje. Stejně tak se před výpočtem. Je to kompromis prohlížet teď, skladování náklady a náklady, které dostanete, když je potřeba.
  • „Třídění cache“ je apt název.
  • Nevím.

Také při mezipaměti věci, mezipaměti je nanejvýš generické možnou úroveň. Některé věci by mohl být uživatel specifické (například výsledky pro vyhledávací dotaz), kde jiní by mohli být uživatel agnostik, jako je prohlížení katalogu. Oba mohou těžit z mezipaměti. Katalog Dotaz může být častější a trochu ušetřit pokaždé, a vyhledávací dotaz může být drahé a ušetřit spoustu několikrát.

Odpovězeno 09/02/2011 v 08:00
zdroj uživatelem

hlasů
0

Existuje tolik způsobů, jak to udělat, aby se kůže příslovečná kočičí. Tak tady je pár mých.

Pokud váš původní dotaz je drahé, který tvrdí, že je, pak vytvořit jinou tabulku případně tabulku paměti vyplnění ji s výsledky vaší drahé a zřídka spuštění hlavního dotazu.

Tato druhá tabulka by pak mohly být dotazovány na každém pohledu a třídění je stejně jednoduché jako nastavení vhodného řazení.

Jak je vyžadováno repopulate druhé tabulky s výsledky z první tabulky, a tím zachovat data čerstvé, ale minimalizovat používání drahého dotazu.

Případně, pokud chcete, aby se zabránilo i připojení k db pak byste mohli uložit všechna data v PHP pole a uložit jej pomocí Memcached. to by bylo velmi rychle a za předpokladu, vaše seznamy nebyly příliš velký bude méně náročná na zdroje. a může být snadno třídit.

DC

Odpovězeno 11/02/2011 v 05:19
zdroj uživatelem

hlasů
0

Základní předpoklady:

  • Slevy jsou týdenní
  • Můžeme očekávat, že místo pro změnu zřídka ... asi každý den?
  • Můžeme kontrolovat aktualizace databáze s éteru API nebo reagují pomocí spouštěčů

Pokud se na staveništi změní na denní bázi, domnívám se, že všechny stránky jsou staticky generovány přes noc. Jeden dotaz pro každý druh řádu iteruje a dělá všechny související stránky. Dokonce i v případě, že jsou dynamické prvky, pravděpodobné, že je lze řešit tím, že zahrnuje statické prvky stránky. To by poskytlo optimální stránky služby a bez zatížení databáze. Ve skutečnosti, mohli byste vytvářet samostatné stránky a Před / Další prvky, které jsou zahrnuty do stránek. To může být šílenější 200 způsobů, jak třídit, ale s 3 Jsem velký fanoušek toho.

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

Pokud z nějakého důvodu to není možné, tak bych se uchylují k zapamatování. Memcache je populární pro tento druh věc (slovní hříčka!). Je-li něco, co tlačil do databáze, můžete vydat spoušť aktualizovat mezipaměť se správnými hodnotami. Udělejte to stejným způsobem, jako byste v případě, jako by vaše aktualizovaná položka existoval do 3 spojových seznamů - znovu sestavit podle potřeby (this.next.prev = this.prev, atd). Z toho, pokud mezipaměť není přeplnění, budete tažení jednoduchých hodnot z paměti do primárního klíče módy.

Tato metoda bude mít nějaké extra kódování na vybraných a aktualizace / insert metod, ale to by mělo být poměrně minimální. Na konci, budete vzhlédl [id of tomatoes class 1].price.next. V případě, že klíč je v mezipaměti, zlatá. Pokud tomu tak není, vložte jej do vyrovnávací paměti a displejem.

  • Myslíte si, že je to dobré praxe zjistit sousední záznamy pro různé dotazu příkazy? Ano. Je rozumné provádět vzhled dopředných očekávaných připravovaném požadavku.
  • Víte, lepší postupy z hlediska výkonu a jednoduchosti? Víte něco, co dělá to naprosto zastaralé? Doufejme, že výše
  • V teorii programování, je tam název pro tento problém? Optimalizace?
  • Je název „Třídění cache“, je vhodné a srozumitelné pro tuto techniku? Nejsem si jistý, specifické příslušné jméno. Je cache, je cache svého druhu, ale nejsem si jistý, že mi říkal, že máte „třídicí mezipaměť“ by přineslo okamžité porozumění.
  • Existují nějaké uznávané, běžné způsoby, jak vyřešit tento problém? Co říkali? Caching?

Je nám líto mé odkalovacích odpovědi jsou trochu zbytečné, ale myslím, že moje vyprávění řešení by měla být velmi užitečná.

Odpovězeno 11/02/2011 v 18:13
zdroj uživatelem

hlasů
0

Ty by mohly uložit čísla řádků objednané seznamy do názorů , a ty by mohly dosáhnout předchozí a následující položky v seznamu podle čísel řádků (current_rownum + 1) (current_rownum-1) a.

Odpovězeno 12/02/2011 v 14:01
zdroj uživatelem

hlasů
0

Problém / datastructur je pojmenována obousměrný graf nebo by se dalo říci, že máte několik propojených seznamů.

Pokud si myslíte, že to jako propojeného seznamu, můžete jen přidat pole do tabulky položky pro každou třídění a Prev / následujícího klíče. Ale DB osoba tě zabije za to, že je to jako GOTO.

Pokud si myslíte o tom, jak je (bi) směrový grafu, jdete s Jessičina odpověď. Hlavním problémem je, že aktualizace pořadí jsou drahé operace.

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

Změníte-li jeden položky postoj k novému pořadí A, C, B, D, budete muset aktualizovat 4 řádky.

Odpovězeno 13/02/2011 v 02:20
zdroj uživatelem

hlasů
4

Mám představu o něco podobného Jessice. Avšak místo toho, ukládání odkazů na další a předchozí třídění předmětů, můžete uložit pořadí řazení pro každý typ třídění. Chcete-li najít předchozí nebo další záznam, jen ten řádek s SortX = currentSort ++ nebo SortX = currentSort--.

Příklad:

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

Toto řešení by poskytlo velmi krátké doby dotazů, a že zabírají méně místa na disku než Jessičina nápad. Nicméně, jak jsem si jist, že si uvědomujete, náklady na aktualizaci jeden řádek dat je výrazně vyšší, protože budete muset přepočítat a uložit všechny pořadí řazení. Ale přesto, v závislosti na situaci, pokud aktualizace dat jsou vzácné a to zejména v případě, že vždy se stalo ve velkém, pak toto řešení by mohlo být nejlepší.

tj

once_per_day
  add/delete/update all records
  recalculate sort orders

Doufám, že to je užitečné.

Odpovězeno 13/02/2011 v 03:30
zdroj uživatelem

hlasů
0

Omlouvám se, pokud jsem špatně, ale myslím, že chcete zachovat seřazený seznam mezi uživatel získá přístup k serveru. Pokud ano, vaše odpověď může také spočívat v mezipaměti strategie a technologie, nikoli v databázi optimalizace dotazu / schématu.

Můj přístup by byl serializovat () pole, jakmile jeho první vyvolány, a pak mezipaměti, že na odděleném skladovacím prostoru; ať už to je Memcached / APC / pevný disk / MongoDB / atd. a udržet jeho detaily umístění mezipaměti pro každého uživatele individuálně prostřednictvím svých dat relace. Skutečná storage backend bude přirozeně záviset na velikosti pole, které nechcete jít do velkých podrobností o, ale Memcached váhy skvěle na více serverech a Mongo ještě při mírně vyšší latence cenu.

Také neukazují, kolik druh permutace existují v reálném světě; např potřebujete do mezipaměti zvláštní seznamy pro jednotlivé uživatele, nebo můžete globálně mezipaměti za třídění permutace a potom odfiltrovat, co nepotřebujete pomocí PHP ?. V příkladu dáte, já bych prostě do mezipaměti obě variace a obchod, který z těch dvou jsem potřeboval unserialize () v datech relace.

Když se uživatel vrátí na místo, zkontrolujte Time To Live hodnotu mezipaměti dat a pokud stále platí znovu používat. Já bych také spoušť běžící na INSERT ignorovat / UPDATE / DELETE pro speciální nabídky, které jednoduše nastaví pole časového razítka do samostatné tabulky. To by okamžitě ukazují, zda je cache byl zatuchlý a dotaz musel být re-běh na velice nízkých nákladech dotazu. Skvělá věc, o používání pouze spoušť nastavit jedno pole je, že není třeba se obávat, prořezávání starých / nadbytečné hodnoty z této tabulky.

Zda toto je vhodný bude záviset na velikosti dat vracených, jak často byl upraven, a to ukládání do mezipaměti technologie jsou k dispozici na serveru.

Odpovězeno 13/02/2011 v 15:47
zdroj uživatelem

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