Kompleks (yavaş) Veri kümeleri için pagination Stratejileri

5 Cevap php

Karmaşık sorguları içeren veri setlerinin pagination için kullanılan bazı stratejileri nelerdir? (*) saymak 1.5 sn yüzden her sayfa görüntüleme için DB vurmak istemiyorum ~ alır. Şu vea bu sorgu tarafından döndürülen ~ 45k satır vardır.

İşte ben kabul ettik yaklaşımlardan bazıları şunlardır:

  • Satır sayısı önbelleğe ve bunu her X dakikada bir güncelleme
  • Limiti (ve ofset) satır (örneğin) 41 sayıldı ve "1 2 3 4 ..." gibi sayfa seçiciyi görüntülemek; o zaman herkes aslında 4. sayfaya giderse recompute ve görüntüler "... 3 4 5 6 7 ..."
  • Satır kez saymak ve kullanıcının oturumunda depolamak alın
  • Sayfa seçici kurtulmak ve sadece bir "Sonraki Sayfa" bağlantısı var olsun

5 Cevap

Ben bir milyondan fazla sayfa izlenimi bir gün bir site için PHP ve MySQL kullanarak bir kaç Sayfalandırması stratejileri mühendisi yaşadım. I aşamalarında stratejiyi persued:

Multi-column indexes Ben bir hayata görünümü denemeden önce bunu yapmalıydım.

Generating a materialized view. Ben kullanıyordum belge tabloları ortak bir denormalizasyon yaptım bir cron işi yarattı. I SELECT ... INTO OUTFILE ... olur ve ardından yeni bir tablo oluşturmak ve döndürün:

SELECT ... INTO OUTFILE '/tmp/ondeck.txt' FROM mytable ...;
CREATE TABLE ondeck_mytable LIKE mytable;
LOAD DATA INFILE '/tmp/ondeck.txt' INTO TABLE ondeck_mytable...;
DROP TABLE IF EXISTS dugout_mytable;
RENAME TABLE atbat_mytable TO dugout_mytable, ondeck_mytable TO atbat_mytable;

Bu mytable minimuma aşağı sürmüştür üzerinde yazma kilidi zaman muhafaza ve sayfalama sorguları atbat hayata bakış uzak çekiç olabilir. Ben önemsiz olan gerçek manipülasyon, dışarı bırakarak, yukarıdaki basitleştirilmiş ettik.

Memcache Sonra memcache içine bu paginated sonuçları önbelleğe benim veritabanı bağlantısı hakkında bir sarıcı yarattı. Bu büyük bir performans kazanmak oldu. Ancak, yine de yeterince iyi değildi.

Batch generation Ben bir PHP daemon yazdı ve içine sayfalama mantığı ayıklanır. Bu değişiklikleri mytable algılamak ve periyodik web sunucusu dosya sistemi tüm sayfaların en son kayda eski değişti kaydından yeniden olacaktır. mod_rewrite biraz, ben sayfa diskte var olmadığını görmek için kontrol edin ve o kadar hizmet verebilir. Bu da beni Apache If-Modified-Since başlıkları algılar ve 304 yanıt kodları ile yanıt vererek reverse proxying etkin yararlanmak için izin verdi. (Açıkçası, ben kullanıcıları sayfa başına sonuç sayısını, önemsiz bir özelliği seçmek için izin herhangi bir seçeneği kaldırıldı.)

Updated: RE count(*): When using MyISAM tables, COUNT didn't create a problem when I was able to reduce the amount of read-write contention on the table. If I were doing InnoDB, I would create a trigger that updated an adjacent table with the row count. That trigger would just +1 or -1 depending on INSERT or DELETE statements.

RE page-pickers (thumbwheels) Ben sorgu önbelleğe agresif taşındığında, başparmak tekerlek sorguları da önbelleğe ve sayfaları oluştururken toplu geldiğinde, ben geçici tablolar kullanarak oldu - yani tırtıllı işlem yapıldı sorun yok. O aslında sadece büyük sayfa numer gerekli öngörülebilir bir dosya sistemi model oldu çünkü thumbwheel hesaplama bir çok basitleştirilmiş. Küçük sayfa numarası her zaman 1. oldu.

Windowed thumbweel Bir pencereli ayar düğmesi için yukarıda vermek örneği (<< 4 [5] 6 >>) Eğer sayfaların maksimum numarasını bildiğiniz tüm bu yüzden de uzun herhangi bir sorgu olmadan yapmak oldukça kolay olmalı .

Benim önerim her sorguda gerek daha 1 satır için MySQL sormak, ve next page-bağlantıyı göstermek için olsun veya olmasın set sonucu satır sayısına göre karar veriyoruz.

MySQL LIMIT sorguları optimize oldukça iyidir.

Yani LIMIT maddesini karşılamak için yeterli filesort tampon vb, uygun katılmak tampon alır demektir.

Ayrıca 45k satır ile muhtemelen tam sayısı gerekmez unutmayın. Yaklaşık sayıları endeksli alanlarda ayrı sorguları kullanarak anladım olabilir. Bu sorguyu Say:

SELECT  COUNT(*)
FROM    mytable
WHERE   col1 = :myvalue
        AND col2 = :othervalue

Bu bir ile tahmin edilebilir:

SELECT  COUNT(*) *
        (
        SELECT  COUNT(*)
        FROM    mytable
        ) / 1000
FROM    (
        SELECT  1
        FROM    mytable
        WHERE   col1 = :myvalue
                AND col2 = :othervalue
        LIMIT 1000
        )

, Çok daha verimli olarak gerçekleştirilmiş olan MyISAM.

Eğer karmaşık bir sorgu bir örnek verecek olursak, belki ben onun sayfalandırma geliştirmek konusunda daha kesin bir şey söyleyebiliriz.

Ben hiçbir şekilde bir MySQL uzman değilim, ama belki de (*) COUNT vazgeçerek ve COUNT (id) ile önde gidiyor?