PHP forumları - nasıl okunmamış tartışmalar / konu / mesaj ile başa çıkmak için

6 Cevap php

Ben bu soruyu burada birkaç kez istendi, ancak cevapların hiçbiri beni memnun etmişti biliyorum. Hemen hemen hepsi tüm maliyet kaçınmak istiyorum veritabanı ile ilgili büyük bir okuma / yazma işlemi, dahil olmasıdır.

Okunmamış tartışmalar / konu / mesaj hakkında düşünmek için bir çok şey var. Ben nasıl yapmak gibi forum sistemleri MyBB, vBulletin, Invision Power Board, Vanilla, phpBB, bilmiyorum vs, o sorunu ile başa çıkmak, bu yüzden çocuklar o deneyiminizi okumak istiyorum. Ben sadece bunun için bir veritabanı tablosunu kullanarak basit bir yol olduğunu biliyorum, ama toplum her ay 10.000 'den fazla üyesi ve 1000 yeni konular olduğunda çok büyük bir okuma / yazma içerecektir. Bu zor, ama sunucunun aşırı yüklenmesini önlemek için bir yol olmalıdır.

Yani, diğer forum sistemleri onunla nasıl başa ne bu sorun için en iyi uygulamalar olarak bulmak, hem de do?

6 Cevap

Bir sürü seçenek yoktur.

  1. her kullanıcı tarafından her okuyucu konu işaretleyin.

    • Dezavantajları: a lot of rows in very active forums
    • Avantajları: Every user knows with post has read or not.
  2. her kullanıcı tarafından her okunmamış konu işaretleyin.

    • Dezavantajları: a lot of space with "unreaded" rows if there is inactivity of a lot of users
    • Çözümler: bir ömür boyu zaman damgası eklemek ve bir cron ile eski kayıtları silmek
    • Avantajları: Every user knows with post has read or not.
  3. göstermek olmadığını belirlemek için damgaları olarak kullanmak okunmamış ya da değil.

    • Dezavantajları: The users don't know with are the real unread threads, the marks only show the "new trheads" since the last login
    • Avantajı: yerden tasarruf

Diğer alternatif çözüm karıştırma, yani

Onlar X günden eski olmayan ve kullanıcı için readed olarak işaretlenmiş bir satır yoksa 1 ve 3) "okunmamış" olarak konu göstermektedir. Onlar bir şey etkiler olmadan eski X gün olduğunda satırlar silinebilir "okumak".

Avantajları

  • okunmamış konuları belirlemek için kullanılan daha az aralıklı

Dezavantajları

  • sistemi temiz tutar bir cron oluşturmak
  • Onlar x günden konuları olders okursanız kullanıcıları bilmiyorum.

Avantajları

  • Her kullanıcı, "yeni mesaj" okumak ya da hangi bilir.

Orada ... başka.

Hiyerarşik bir forum yapısı (yönetim kurulu> bölüm> iplik, vb) için ayrıntılı okundu / okunmadı verileri saklamak için başka bir yolu. O olmadan yapar a) önceden doldurmak / okunmamış bilgileri okumak ve b) her zamankinden daha fazla saklamak zorunda kalmadan sahip daha U * U kullanıcı sayısı, ve M onun kötü durumda, (M / 2) satır toplam veritabanında mesajların sayısı (ve genellikle çok, bu çok daha az)

Ben bir süre önce bu konuyu araştırdım. Ben SMF / phpBB onlar kullanıcı okuma geçmişini saklamak nasıl biraz "hile" olduğunu buldu. Onların şema son damgaları veya belirli bir yönetim kurulu okundu olarak işaretlenmiş mesaj kimliği ya da depolanmasını destekler, forum, subforum, konu (ya da tarayıcı tarafından doğrudan izlendi) şöyle:

[User_id, tahta, last_msg_id, last_timestamp]

[User_id, tahta, forum, last_msg_id, last_timestamp]

[User_id, tahta, forum, subforum, last_msg_id, last_timestamp]

[User_id, tahta, forum, subforum, konu, last_msg_id, last_timestamp]

Bu "okuma" olarak kullanıcılar, vb gibi belirli panoları, forumlar, konular işareti sağlar. Bu gerektirir, ancak, (okuma, ya da aktif "okundu olarak işaretini" linkine tıklayarak ya) ve phpBB durumunda kullanıcı adına eylem, ya sen "Ben bu özel gördük demek için zerreliğini vermez mesajı, ancak belirli değil mesajı. " Ayrıca, (bir iplik son etkinliği görüntüleme) ilk konudaki son mesajı okumak ve hemen iplik kalanını okudum kabul ediyoruz durum olsun.

Bu şimdiye kadar tek bir yazı (Varsayılan görünümleri bir konunun son sayfasında 20 + mesaj için ayarlanmıştır) inceliyorsunuz nadir çünkü bu gibi şeyleri saklamak için SMF ve phpBB için çalışıyor. Ancak, daha dişli forumlarda (iletilere bir anda görüntülemekte olduğunuz özellikle forumlar) için, bu ideal daha azdır. Bu sistemin Kullanıcılar, bir mesaj okudu ama başka varsa büyük olasılıkla bir sürü bakım, ve sadece gerçekten onlar sadece istediği okundu olarak tüm bir bölümü, işaretlemek mümkün hantal düşünebilirsiniz okundu olarak işaretlenmiş bir kaç.

Böyle dizilerini mesajları saklamak: [User_id, lower_msg_id, upper_msg_id]

Kullanıcı tarih log aşağıdaki gibi korunur:

Sayfa görünümü üzerine bir işlev User_id current_msg_id lower_msg_id ve upper_msg_id arasında bir kayıt olup olmadığını görmek için bakar. Varsa, o zaman bu sayfayı okuyun ve hiçbir eylem ihtiyaçları alınır. Değil varsa, o zaman başka bir sorgu current_msg_id (current_msg_id == lower_msg_id-1), ya da upper_msg_id daha birini (current_msg_id == 1 upper_msg_id) lower_msg_id fazla bir ya az ise bu sefer belirlenmesi, çıkarılacak vardır. Bu, büyümek böyledir bizim "okumak" ya da 1 ile sınırını "görüldü". Biz bir uzak lower_msg_id veya uppper_msg_id gelen iseniz, o zaman biz bu yönde 1 ile başlığın büyür. Bizim demet dizi büyüyen değilseniz, o zaman yeni bir başlığın takın, [User_id, current_msg_id, current_msg_id].

Iki başlığın aralıkları birbirine yaklaştığı zaman köşe durumdur. Bu durumda, alt sınır ve başlığın üst başlığın sınırı arasındaki arama üzerine, üst başlığın üst sınırına alt başlığın üst sınırını ayarlayarak iki sınırları birleştirme ve üst başlığın silin.

PHP kod örneği:

function seen_bounds( $usr_id, $msg_id ) {

    # mysql escape
    $usr_id = mres( $usr_id );
    $msg_id = mres( $msg_id );

    $seen_query = "
        SELECT
            msb.id,
            msb.lower_msg_id,
            msb.upper_msg_id
        FROM
            msgs_seen_bounds msb
        WHERE
            $msg_id BETWEEN msb.lower_msg_id AND msb.upper_msg_id AND
            msb.usr_id = $usr_id
        LIMIT 1;
    ";

    # See if this post already exists within a given
    # seen bound.
    $seen_row = query($seen_query, ROW);

    if($seen_row == 0) {
        # Has not been seen, try to detect if we're "near"
        # another bound (and we can grow that bound to include
        # this post).
        $lower_query = "
            SELECT
                msb.id,
                msb.lower_msg_id,
                msb.upper_msg_id
            FROM
                msgs_seen_bounds msb
            WHERE
                msb.upper_msg_id = ($msg_id - 1) AND
                msb.usr_id = $usr_id
            LIMIT 1;
        ";

        $upper_query = "
            SELECT
                msb.id,
                msb.lower_msg_id,
                msb.upper_msg_id
            FROM
                msgs_seen_bounds msb
            WHERE
                msb.lower_msg_id = ($msg_id + 1) AND
                msb.usr_id = $usr_id
            LIMIT 1;
        ";

        $lower = query($lower_query, ROW);
        $upper = query($upper_query, ROW);

        if( $lower == 0 && $upper == 0 ) {
            # No bounds exist for or near this. We'll insert a single-ID
            # bound

            $saw_query = "
                INSERT INTO
                    msgs_seen_bounds
                (usr_id, lower_msg_id, upper_msg_id)
                VALUES
                ($usr_id, $msg_id, $msg_id)
                ;
            ";

            query($saw_query, NONE);
        } else {
            if( $lower != 0 && $upper != 0 ) {
                # Found "near" bounds both on the upper
                # and lower bounds.

                $update_query = '
                    UPDATE msgs_seen_bounds
                    SET
                        upper_msg_id = ' . $upper['upper_msg_id'] . '
                    WHERE
                        msgs_seen_bounds.id = ' . $lower['id'] . '
                    ;
                ';

                $delete_query = '
                    DELETE FROM msgs_seen_bounds
                    WHERE
                        msgs_seen_bounds.id = ' . $upper['id'] . '
                    ;
                ';

                query($update_query, NONE);
                query($delete_query, NONE);
            } else {
                if( $lower != 0 ) {
                    # Only found lower bound, update accordingly.
                    $update_query = '
                        UPDATE msgs_seen_bounds
                        SET
                            upper_msg_id = ' . $msg_id . '
                        WHERE
                            msgs_seen_bounds.id = ' . $lower['id'] . '
                        ;
                    ';

                    query($update_query, NONE);
                }

                if( $upper != 0 ) {
                    # Only found upper bound, update accordingly.
                    $update_query = '
                        UPDATE msgs_seen_bounds
                        SET
                            lower_msg_id = ' . $msg_id . '
                        WHERE
                            msgs_seen_bounds.id = ' . $upper['id'] . '
                        ;
                    ';

                    query($update_query, NONE);
                }
            }
        }
    } else {
        # Do nothing, already seen.
    }

}

Current_msg_id belirli bir kullanıcı (bir NOT SQL açısından sorgusu VAR) için herhangi lower_msg_id ve upper_msg_id arasında yok nerede okunmamış mesajların arıyor bulgudur. Bir ilişkisel veritabanı uygulama sorguları en verimli değil, ama agresif indeksleme ile çözülebilir. Örneğin, aşağıdaki mesaj olduğu tartışma alanı ("item") göre gruplandırma, belirli bir kullanıcı için okunmamış mesajları sayma için bir SQL sorgusu:

$count_unseen_query = "
    SELECT 
        msgs.item as id,
        count(1) as the_count
    FROM msgs
    WHERE
    msgs.usr != " . $usr_id . " AND
    msgs.state != 'deleted' AND
    NOT EXISTS (
       SELECT 1 
       FROM 
          msgs_seen_bounds msb
       WHERE 
          msgs.id BETWEEN msb.lower_msg_id AND msb.upper_msg_id
          AND msb.usr_id = " . $usr_id . "
    )
    GROUP BY msgs.item
    ;

Daha fazla kullanıcı foruma, geniş her demet tarafından okundu olarak işaretlenmiş sınırları, ve daha az tuplelar depolanmak zorunda okumaya. Kullanıcılar okunmamış vs okumak doğru bir sayı alabilirsiniz, ve oldukça kolay vs vs her forumda, subforum, konu okunmamış okumak görmek için toplanmış olabilir

Yaklaşık 2000 + mesaj, küçük bir forum önüne alındığında, aşağıdaki kullanıcılar (kullanıcı etkinliği yaklaşan) giriş yaptıktan kez sayısına göre sıralanır saklanan dizilerini, sayısı ile ilgili kullanım istatistikleri. Sütun "num_bounds" geçmişini görüntüleme kullanıcının "num_posts_read" saklamak için gerekli dizilerini sayısıdır.

id  num_log_entries num_bounds num_posts_read num_posts
479             584         11           2161       228
118             461          6           2167       724
487             119         34           2093       199
499              97          6           2090       309
476              71        139            481        82
480              33         92            167        26
486              33        256            757       154
496              31        108            193        51
490              31         80            179        61
475              28        129            226        47
491              22         22           1207        24
502              20        100            232        65
493              14         73            141         5
489              14         12           1517        22
498              10         72            132        17

Ben bu herhangi bir forumda özel uygulamasını ama benim kendi özel biri görmedim, ve o küçük bir biri. Herkesten uygulanan, ya da bu özellikle büyük ve / veya aktif forumda, başka bir yerde hayata gördü eğer ilgi duyarım.

Selamlar,

Kaiden

Neden söz konusu?

Ben okunmamış mesajları almak için herhangi bir I / O ile bir sorunu görmüyorum. Bu canlı olmak zorunda değildir. Bir önbellek değere dayalı bir 15 dakikalık bir gecikme çalışacak.

Yani okunmamış dişler için sadece

Sahte kod ..

$result = SELECT id,viewcount from my_forum_threads

$cache->setThreads($result['id'],$result['viewcount']);

Sonra bir sayfa yük sadece önbellek değerlerini almak yerine tekrar veritabanı sorgulama. Onun gerçekten hiç büyük bir sorun.

Benim web sitesinde ortalama sayfa 20 mysql sorguları sürüyor. Ben önbelleğe zaman sadece 2-4 sorgularını.

Ben biliyorum, neredeyse herhangi bir forum, bir iş parçacığı / mesaj "okunmamış" ya da değil olarak kabul edilmelidir olup olmadığını belirlemek için referans damgası çeşit kullanacaktır. Bu zaman damgası genellikle foruma önceki ziyaretimde üzerinde yapılan son eylemin tarih / zaman.

Yani yani tutmak. Bir previous_last_action & Kullanıcı tabloda last_action damgası, last_action her kullanıcı eylem, previous_last_action sütun giriş yaparken last_action kez ayarlanır güncellenir (yeni bir oturum oluşturma veya upon - varsa işlevselliği "beni hatırla"). Bir iplik / mesajı okunmamış ise şu anda oturum açmış kullanıcı için previous_last_action de değeri ile bu konu / mesaj oluşturma (veya güncelleme) timestamp karşılaştırmak istiyorsunuz belirlemek için

Sigara tam burada bir PHP-cevap, ama (açıklamadan, ben bu ürün ile bağlı olduğum nedeniyle kurallara) bizim asp.net-based forum bunu nasıl

  1. We use cookies, not the database.
    • Disadvantage kurabiye - "çapraz cihaz" değil (başka bir bilgisayardan ziyaret okunmamış gibi her şeyi gösterir)
    • Advantage - hiçbir büyük DB okur / yazar. Ve takibi de "misafir" kullanıcılar için çalışıyor! Bu harika.
  2. Biz her konu için { topicID, lastReadMessageID } çiftleri kullanıcı ziyaretleri ile bir çerez saklamak.
  3. If the data for a particular topic is not found in the cookie we assume the topic is either:
    • tam okunmamış (, konunun son mesajı lastReadMessageID (2 MAX büyükse)
    • tamamen okunup (aksi takdirde)

Bu bazı küçük kusurları vardır, ama iş yok.

PS. Ayrıca, bazı çerezleri kullanarak kullanıcının bilgisayarında (Ben şahsen bu nefret) üzerinde çöp bırakır diyebilirsiniz, ama biz ortalama bir kullanıcı başında yaklaşık 20 konu izler öğrendim, bu yüzden az 200 bayt alır bu yüzden konu başına yaklaşık 10 bayt alır kullanıcının sabitdisk üzerinde.

IPB nasıl yapar (bence) üzerinde hızlı bir cevap:

Okumak gibi yapılandırma miktarı (varsayılan 30 gün) daha eski tüm mesajlar otomatik olarak işaretlenir. Bir cronjob yönetilebilir boyutu tutmak için her kullanıcı bu kuru erik.

Az 30 gün yaşlı tüm mesajlar her bir kullanıcı kimliği + kategori için bir JSON giriş olarak izlenir. Ör: 1000 aktif kullanıcı ile 12 kategori = 12.000 satır maksimum.

Orada bir "okunmamış sayısı" alan Forum Ev, diyelim ki, hızlı aramalar için, ya da başka bir yerde sadece bir sayı gereklidir.

Ben gerçek MySQL depolama tamamen kapalı olabilir. Ben bu belgelerine bulamadı, ama ben veritabanı üzerinden çıkardı ve / okuma / okunmamış ipler (tablo: core_item_markers, referans için) gibi baktı / bir tablo gördüm. Ama hibrid yaş / mysql model üzerinde olumlu duyuyorum.