Sonraki ve önceki elemanı için optimize sorgular

12 Cevap php

Ben tam bir sorgu çalıştırmadan bir kaydın önceki ve sonraki kayıtları almak için en iyi yolu arıyorum. Ben yerde tam uygulanan çözüm var, ve orada bu dışarı yapmak için daha iyi bir yaklaşım olup olmadığını bilmek istiyorum.

Adlı bir hayali manav için bir web sitesi inşa ediyoruz diyelim. Onun HTML sayfalarına ek olarak, her hafta, onun sitesinde özel teklifler listesini yayımlamak istiyor. O, bu teklifler gerçek bir veritabanı tablosunda ikamet istiyor ve kullanıcılar üç şekilde teklifleri sıralamak mümkün olmalıdır.

Her madde de teklif daha, metinsel bilgi ve "önceki" ve "sonraki" düğmeleri ile bir detay sayfasına sahip olması gerekir. "Önceki" ve "sonraki" butonları komşu girişleri depending on the sorting the user had chosen for the list işaret etmek gerekir.

alt metni

Açıkçası, "Domates, Sınıf I" için "next" düğmesine ilk örnekte "Elmalar, 1. sınıf", "Armut, sınıf I" ikinci ve üçüncü hiçbiri olmak zorundadır.

Ayrıntı görünümünde görev sadece bilgi olarak listenin sıralama düzeni (Şimdi bunu bir GET parametresi ile ?sort=offeroftheweek_price olsun diyelim ve güvenlik etkilerini görmezden ile, to determine the next and previous items without running a query every time olduğunu .)

Açıkçası, sadece bir parametre olarak bir sonraki ve bir önceki elemanlarının kimliklerini geçen akla gelen ilk çözümdür. Sonuçta, biz zaten bu noktada kimliklerini biliyoruz. Ama, bu burada bir seçenek değildir - bu benim gerçek dünyada kullanımı pek çok olayda bu basitleştirilmiş örnekte iş, ama olmaz.

Benim CMS Geçerli Benim yaklaşım ben "sıralama cache" adında bir şey kullanıyor. Bir liste yüklendiğinde, ben sortingcache adında bir tablodaki kayıtların içinde öğe pozisyonları saklayın.

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

Açıkçası, items sütun gerçekten sayısal kimlikleri ile doldurulur.

Detay sayfasında, ben şimdi, uygun sortingcache kaydına erişmek items sütunu alıp, patlayabilir, geçerli öğe kimlik aramak, ve önceki ve sonraki komşusu dönün.

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

Bu, besbelli pahalı sadece kayıtları sınırlı sayıda için çalışıyor ve gereksiz verileri oluşturur, ama gerçek dünyada, listeleri oluşturmak için sorgu her ayrıntı görünümünde çalışan, (o) çok pahalı dışında olduğunu varsayalım soru ve some önbelleğe gereklidir.

My questions:

  • Bu sorgu emir değişen için komşu kayıtları bulmak için iyi bir uygulama olduğunu düşünüyor musunuz?

  • Performans ve basitlik açısından daha iyi uygulamaları biliyor musunuz? Bu tamamen demode kılan bir şey biliyor musunuz?

  • Programlama Teorik olarak, bu sorun için bir isim var mı?

  • Adı "önbelleğini Sınıflandırma" bu teknik için uygun ve anlaşılır?

  • Bu sorunu çözmek için herhangi bir kabul, ortak desenler var mı? Ne denir?

Note: Benim soru listesi oluşturma hakkında değil, ya da ayrıntı görünümü görüntülemek için nasıl. Bunlar sadece örnekler. Benim sorum bir re-sorgu imkansız olduğu zaman bir kaydın komşularını belirleme basic functionality, ve oraya en hızlı ve en ucuz yoludur.

Şey belirsiz ise, bir yorum bırakın ve ben açıklamak lütfen.

Bir lütuf Başlangıç ​​- belki orada bu konuda biraz daha bilgi var.

12 Cevap

İşte bir fikir. Son kullanıcı görüntülemek için verileri seçtiğinde bakkal ekler / yeni teklifler yerine güncellemeleri ne zaman bir güncelleme için pahalı işlemleri boşaltması olabilir. Bu tür verileri işlemek için dinamik olmayan bir yol gibi görünebilir, ama hızını arttırabilir. Ve bildiğimiz gibi, performans ve diğer kodlama faktörler arasında bir ticaret her zaman vardır.

Her fırsat ve her tür seçenek için sonraki ve önceki tutmak için bir tablo oluşturun. (Her zaman üç çeşit seçenek var eğer Alternatif olarak, teklif tabloda bu saklamak olabilir - sorgu hızı veritabanını denormalize için iyi bir nedendir)

Yani bu sütunlar olurdu:

  • Sıralama (Boylanmamış, fiyat, sınıf ve Fiyat Detaylar) Tip
  • Teklif No
  • Önceki Kimliği
  • Sonraki Kimliği

Teklif detay sayfası için detaylı bilgi veritabanından sorgulanan zaman NextID ve PrevID sonuçlarının parçası olacaktır. Yani sadece her ayrıntı sayfası için bir sorgu gerekir.

Her zaman bir teklif, eklenen güncelleştirildi veya silindi, sen sorttype tablonun bütünlüğü / doğruluğunu onaylayan bir işlemi çalıştırmak gerekir.

Ben Jessica biraz benzer bir fikrim var. Ancak, bunun yerine önceki ve sonraki sıralama öğelere bağlantılar depolanması, her çeşit türü için sıralama düzeni saklayın. - Bir önceki veya sonraki kaydı bulmak için, sadece SortX = currentSort + + veya SortX = currentSort ile satır olsun.

Örnek:

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

Bu çözüm çok kısa bir sorgu kez doğuracak, ve Jessica'nın fikri daha az disk alanı alacaktı. Ben fark eminim gibi her tür siparişleri yeniden hesaplamak ve saklamak zorunda beri Ancak, bir satır veri güncelleme maliyeti, özellikle yüksektir. Ama yine de, durumunuza bağlı olarak, veri güncellemeleri nadirdir ve onlar her zaman toplu olarak gerçekleşmesi, özellikle eğer, o zaman bu çözüm iyi olabilir.

yani

once_per_day
  add/delete/update all records
  recalculate sort orders

Bu yararlı olduğunu umuyoruz.

Ben senin soru yanlış olabilir - lütfen bana bildirin.

Soyut, bunu yapmanın en iyi yoludur:

Maintain your database as three utterly separate, completely sorted, separate systems.

Ben "sistemler" demek nereden {ki, "bir tablo" olarak, dolayısıyla üç tamamen ayrı tablolar, ya da şu anda bir repreesntation için ne var eğer "tabloları bir grup" olabilir olabilir. Diğer bir deyişle, temel olarak three separate databases, olduğu gibi.}

Bu mantıklı mı? Yani diyelim ki, veritabanını değiştiren bazı yeni öğe eklemek için var diyelim. Aslında, o zaman tüm üç tablo için üç farklı şekilde yeni bir öğe eklemek gerekir. Tüm işlemleri (silme, vb) tüm üç tablo üzerinde çalışmak gerekir. Ayrıca her şeyin iyi durumda olduğundan emin olmak için bir uzlaştırıcı olmalıdır. Bunu kullanmak yapmak için saklı yordamlar, vb, ya da ne gibi bariz teknolojinin herhangi bugün trendy.

Bu büyük veritabanları ile tamamen standart işletim prosedürü olduğunu ve size hiçbir sorun vermelidir.

Web kullanıcı arar Sonra, iş saçmadır.

I'm surprised nobody else mentioned this totally obvious standard approach belkide ben seni tamamen yanlış?


Ayrıca Pekka, ne diyorsun, bir kullanıcı tıklayarak anlamında ise açıklamak "sonraki 50" "önceki 50" sadece modern bir web sayfasında sonuç herhangi bir liste gibi. Lütfen Bana haber ver!

Bu durumda, elbette, tabii ki, you have to make a separate table/cache/session/whatever for each user who comes along (5 dakika kullanmama sonra bunları silin).

Bu normal bir şey olduğunu kesinlikle her "sayfa ileri / sayfa geriye" web üzerinde sonuçları web sayfası şimdi en az 10 yıldır yok!!

Eğer google veya herhangi bir arama sonucunu kullanmak her zaman size dalarken kadar var olan kendi büyük bir geçici veritabanı sistemi olsun.

Ne soruyorsun ise ... Eğer bir oturum listesinde bu fikri bağımsız (bu web bugünlerde tabii olarak nasıl işliyor farkında değil) icat ve bu şekilde yapmak için Tamam - o zaman evet! !, sen google ya da tüm web üzerinde herhangi bir next-previous-sayfasını kullanmak her zaman bu oluyor sadece ne olduğunu! Sen bağımsız bir düşünce kuruluşu olan tüm modern sayfa-geriye-ileriye arama çalışması yolu. Kesinlikle her kullanıcı için "cache" ile devam.

I've had nightmares with this one as well. Your current approach seems to be the best solution even for lists of 10k items. Caching the IDs of the list view in the http session and then using that for displaying the (personalized to current user) previous/next. This works well especially when there are too many ways to filter and sort the initial list of items instead of just 3.
Also, by storing the whole IDs list you get to display a "you are at X out of Y" usability enhancing text.
JIRA's previous/next

Bu arada, bu JIRA de yaptığı budur.

Doğrudan soruları cevaplamak için:

  • Filtre / sıralama ve öğe türleri daha karmaşık karga zaman eklenen kod karmaşıklığı olmadan terazi çünkü Evet bu iyi bir uygulamadır. Ben "sonsuz" filtre / sıralama varyasyonları ile 250k makale ile bir üretim sistemi kullanıyorum. 1000 önbelleklenebilir kimlikleri Kırpma de kullanıcı muhtemelen (O, muhtemelen geri dönün ve aramayı daraltmak veya paginate olacak) prev veya 500'den fazla kez tıklatın sonraki asla beri bir olasılıktır.
  • Ben daha iyi bir yol bilmiyorum. Sıralar nerede sınırlı ve bu (hiçbir http oturumu ile) bir kamu sitesi olsaydı ama sonra muhtemelen denormalize ediyorum.
  • Bilmiyorum.
  • Evet, sıralama önbellek iyi geliyor. Projemde ben "arama sonuçlarında bir sonraki / önceki" veya "arama sonuçlarında gezinme" diyoruz.
  • Bilmiyorum.

Genel olarak, ben endeksler verileri denormalize. Onlar aynı satırlar saklanabilir olabilir, ama hemen hemen her zaman veri için ayrı bir yolculuk yapmak, sonra benim sonuç kimlikleri almak. Bu, çok basit bir veri önbelleğe alma hale getirir. Gecikme düşük ve yüksek bant genişliği olduğu PHP çok önemli değil, ama bu tür sitenin çok JavaScript işlenen bir AJAX web sitesi olarak bir yüksek gecikme, düşük bant genişliği uygulaması, varsa böyle bir strateji çok yararlıdır.

Ben her zaman sonuç listeleri önbelleğe ve ayrı ayrı sonuçlar kendileri. Şey bir liste sorgu sonuçlarını etkiler ise, liste sonuçlarının önbellek yenilenir. Şey sonuçlarını kendilerini etkilemesi durumunda, bu özel sonuçlar yenilenir. Bu bana etkili önbelleğe alma sonucunda, her şeyi yenkimliken oluşturmak zorunda kalmadan tek ya da güncellemek için izin verir.

Sonuç benim listeleri nadiren değişiklik beri, ben aynı anda tüm listeleri oluşturmak. Bu ilk tepkisi biraz daha yavaş yapabilir, ancak (tüm listeleri tek bir önbellek girdisi olarak depolanır) önbellek serinletici kolaylaştırır.

Ben tüm liste önbelleğe sahip olduğundan, bu veritabanını tekrar gözden geçirmeden komşu öğeleri bulmak için önemsiz bulunuyor. Şans ile, bu öğeler için veriler de önbelleğe alınır. JavaScript verileri sıralama Bu özellikle kullanışlıdır. Ben zaten istemckimlike önbelleğe bir kopyasını varsa, ben anında çare olabilir.

Özellikle sizin sorularınızı yanıtlamak için:

  • Evet, maliyeti, düşük ve yenkimliken hesaplamak için maliyeti yüksek, özellikle istemci sonraki erişmek için muhtemel olan her türlü bilgiyi vaktinden komşuları öğrenmek için harika bir fikir, veya. O zaman sadece hız karşı ekstra öncesi hesaplama ve depolama kapalı bir ticaret.
  • Performans ve basitlik bakımından, mantıksal olarak farklı şeyler olduğunu kalede şeyleri birlikte kaçının. Indeksler ve veri, farklı farklı zamanlarda değişmiş olması muhtemeldir (örneğin yeni bir veri ekleyerek endeksleri etkileyecektir, ancak mevcut veri) dolayısıyla, ve ayrı ayrı erişilebilir olmalıdır. Bu biraz daha az verimli bir tek dişli açısından olabilir, ama birlikte bir şey kravat her zaman, etkinliğini ve asychronosity (ölçekleme anahtar asychronosity olduğu) önbelleğe kaybetmek.
  • Vaktinden veri almak için Terim önokuma olduğunu. Önokuma erişim ya da arka planda bir zamanda gerçekleşmesi, ancak önceden getirilen veriler aslında gerekli önce olabilir. Aynı şekilde ön-hesaplama ile. Bu gerektiğinde almak için artık maliyet ticaret-off, depolama maliyeti ve maliyeti bulunuyor.
  • "Sorting cache" is an apt isim.
  • Bilmiyorum.

Şeyleri önbelleğe zaman da, mümkün olan en genel düzeyde onları önbelleğe. Bazı şeyler, diğerleri kullanıcı böyle bir katalog tarama gibi, agnostik olabilir kullanıcı özel (örneğin bir arama sorgusu için sonuçları gibi) olabilir. Hem önbelleğe yararlanabilir. Katalog sorgu sık ve biraz her zaman kazanmak ve arama sorgusu pahalı olması ve bir sürü birkaç kez kaydedebilirsiniz olabilir.

Ben doğru anladım emin değilim, o kadar değilse, sadece söyle ;)

Givens kriteri listesi ve bu listede ofset akımı için sorgu olduğunu, diyelim, yani biz bir $query ve bir $n.

Sorguları en aza indirmek için çok bariz bir çözüm, bir kerede tüm verileri almak olacaktır:

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

Bu deyim geçerli sıralama sırayla, önceki mevcut ve veritabanından sonraki elemanları getirir ve ilgili değişkenlere ilgili bilgileri koyar.

Bu çözüm çok basit gibi ama, ben bir şey yanlış varsayalım.

Meşhur kediyi olarak bunu yapmak için pek çok yol vardır. Yani burada benim bir çift vardır.

Your özgün sorgu pahalı ise, hangi sonra muhtemelen pahalı sonuçları ile doldurmamak bir bellek masa başka bir tablo oluşturmak ve nadiren ana sorgu çalıştırdığınızda, öyle söylüyorlar.

Bu ikinci tablo, o zaman her görünümünde sorgulanabilir olabilir ve sıralama uygun sıralama düzenini ayarlama kadar basittir.

Böylece verileri taze tutmak, ancak pahalı sorgu kullanımını en aza indirerek, ilk tablodan sonuçları ile ikinci tablo yeniden doldurmanız gerekli olduğu gibi.

Eğer db bağlanırken bile kaçınmak istiyorsanız dönüşümlü, o zaman bir php dizideki tüm verileri depolamak ve memcached kullanarak saklamak olabilir. Bu çok hızlı ve listeleri verimli bir kaynak olacaktır çok büyük değildi sağlanan olacaktır. ve kolayca sıralanabilir.

DC

Temel varsayımlar:

  • Promosyonlar haftalık vardır
  • Biz site muhtemelen günlük ... seyrek değiştirmek için bekleyebilirsiniz?
  • Biz eter bir API ile veritabanına güncellemeleri denetlemek veya tetikleyiciler aracılığıyla yanıt verebilir

Site günlük olarak değiştirirse, ben tüm sayfaları statik bir gecede oluşturulan öneririz. Bir aracılığıyla her sort-order yinelenir sorgu ve tüm ilgili sayfaları yapar. Dinamik unsurlar olsa bile, oran statik sayfa elemanları dahil ederek onlara adres vardır. Bu optimal sayfa hizmet ve hiçbir veritabanı yükünü sağlayacaktır. Aslında, muhtemelen ayrı sayfalar ve sayfalar dahil edilmiştir Önceki / sonraki unsurları oluşturabilir. Bu sıralamak için 200 yolları ile çılgın olabilir, ama 3 ile ben büyük bir hayranı değilim.

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

Bu mümkün değil nedense, ben ezber başvurmak istiyorum. Memcache şey bu tür (pun!) için popüler. Şey veritabanına itti zaman, doğru değerler ile önbelleğini güncellemek için bir tetikleyici verebilir. Uygun olarak (this.next.prev = this.prev, vb) yenkimliken bağlamak - güncellenen madde 3 bağlantılı listelerinde var sanki eğer olur aynı şekilde yapın. Dışında, sürece önbellek doldurmayın değil gibi, bir birincil anahtar şekilde hafızadan basit değerleri çekerek olacak.

Bu yöntem seçme ve güncelleştirme / ekleme yöntemleri hakkında bazı ekstra kodlama alacak, ama bu oldukça minimal olmalıdır. Sonunda, yukarıya bakıyor [kimlik of tomatoes class 1].price.next. Olacak Bu anahtar önbellek, altın ise. Değilse, önbellek ve ekran içine yerleştirin.

  • Bu sorgu emir değişen için komşu kayıtları bulmak için iyi bir uygulama olduğunu düşünüyor musunuz? Yes. It is wise to perform look-aheads on expected upcoming requests.
  • Performans ve basitlik açısından daha iyi uygulamaları biliyor musunuz? Bu tamamen demode kılan bir şey biliyor musunuz? Hopefully the above
  • In programming theory, is there a isim for this problem? Optimization?
  • Is the isim "Sorting cache" is appropriate and understandable for this technique? I'm not sure of a specific appropriate isim. It is caching, it is a cache of sorts, but I'm not sure that telling me you have a "sorting cache" would convey instant understanding.
  • Bu sorunu çözmek için herhangi bir kabul, ortak desenler var mı? Ne denir? Caching?

Maalesef benim kuyruklanmasız cevaplar tür işe yaramaz, ama benim anlatı çözümleri oldukça yararlı olması gerektiğini düşünüyorum.

Sen row numbers sipariş listelerinin views içine kurtarabilir, ve (current_rownum-1) altındaki listede, önceki ve sonraki öğeleri ulaşabilir ve (current_rownum +1) satır numaraları .

Sorun / datastructur iki yönlü grafik adlandırılır veya birkaç bağlı listeleri var diyebiliriz.

Eğer bir bağlantılı liste olarak düşünürseniz, sadece her sıralama ve önceki / sonraki anahtarı için öğeleri tabloya alanları ekleyebilirsiniz. Ancak DB Kişi GOTO gibi, bunun için seni öldürecek.

Eğer bir (bi-) yönlü grafik olarak düşünürseniz, Jessica'nın cevap ile gitmek. Orada asıl sorun, sipariş güncellemeler pahalı operasyonlar olmasıdır.

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

Eğer yeni sipariş A'ya bir ürün konumunu değiştirmek varsa, C, B, D, 4 adet satır güncellemek zorunda kalır.

Ben yanlış var, ama kullanıcı sunucuya erişen arasındaki sıralı listesini tutmak istiyorum düşünüyorum özür dilemek durumunda. Eğer öyleyse, cevap sıra önbelleğe alma stratejisi ve oldukça veritabanı sorgu / şema optimizasyonu daha teknolojileri yalan olabilir.

, Benim yaklaşım () dizi bir kez onun alınacağını ve daha sonra ayrı bir depolama alanına bu önbelleğe ilk seri olacaktır O / APC / hard-disk / mongodb / vb memcached ve ayrı ayrı kendi oturum verileri üzerinden her kullanıcının kendi önbellek konumu ayrıntılarını korumak olsun. Gerçek depolama backend doğal olarak hakkında çok detaya gitmez dizinin, büyüklüğüne bağlı olacaktır, ama memcached çoklu sunucular üzerinde büyük ölçekler ve biraz daha fazla gecikme pahasına da ileri Mongo.

Ayrıca gerçek dünyada kaç tane tür permütasyon göstermez; örneğin Eğer kullanıcı başına ayrı listeler önbelleğe, ya sonra küresel sıralama permütasyondaki başına önbellek ve PHP üzerinden gerekmez ne filtre gerekiyor?. Verdiğiniz örnekte, ben sadece oturumu veri () unserialize için gerekli iki permütasyon ve mağaza hem de önbelleğe ediyorum.

Kullanıcı siteye döndüğünde, önbelleğe alınan verilerin değerini Live Zaman kontrol ve hala geçerli ise yeniden kullanmak. Ben de INSERT / UPDATE üzerinde çalışan bir tetikleyici / sadece ayrı bir tabloda bir zaman damgası alanı ayarlar özel teklifler için SİL olurdu. Bu hemen önbellek bayat ve sorgu çok düşük sorgu maliyet için yeniden çalıştırmak gerekiyordu belirtmek istiyorum. Yalnızca tek bir alan ayarlamak için tetikleyici kullanımı hakkında çok şey bu tablonun dışında eski / gereksiz değerleri budama konusunda endişelenmenize gerek yok olmasıdır.

Bu uygun olup olmadığını veriler nasıl modifiye edildiğini sık sık, döndü, ve teknolojileri sunucu üzerinde bulunmaktadır ne önbelleğe varlık büyüklüğüne bağlı olacaktır.

Yani iki görevi vardır:

  1. (BY farklı SİPARİŞ seçer) öğelerin sıralı liste oluşturmak
  2. (mümkünse önbelleğe alma ile veritabanından ayrıntıları SEÇ) her öğe hakkında ayrıntılı bilgi gösterir.

Sorun nedir?

PS: sıralı liste sadece PAGER işlevsellik uygulanabilir ihtiyaç çok büyük olabilir eğer. Farklı uygulamaları var olabilir, örneğin Eğer sorgu içine "SINIRI 5" eklemek ve "Show sonraki 5" butonuna sağlamak isteyebilirsiniz. Bu düğmeye basıldığında, "fiyat <0,89 SINIRI 5 NEREDE" eklenir gibi bir durumdur.