Messenger veritabanı (bölüm 2): "kâr amaçlı" bölümlendirme

PostgreSQL veritabanımızın yazışmaları depolamak için yapısını başarıyla tasarladık, bir yıl geçti, kullanıcılar aktif olarak dolduruyor ve şimdi şunları içeriyor: milyonlarca kayıtve... bir şeyler yavaşlamaya başladı.

Messenger veritabanı (bölüm 2): "kâr amaçlı" bölümlendirme
Gerçektir Tablo boyutu büyüdükçe indekslerin “derinliği” de artar. - logaritmik olarak da olsa. Ancak zamanla bu, sunucuyu aynı okuma/yazma görevlerini gerçekleştirmeye zorlar kat kat daha fazla sayfalık veri işliyorbaşlangıçta olduğundan daha fazla.

Burası kurtarmaya geldiği yer bölümleme.

Sharding'den yani verinin farklı veritabanları veya sunucular arasında dağıtılmasından bahsetmediğimizi belirteyim. Çünkü verileri bölmek bile bazı sunucularda zamanla indekslerin “şişmesi” probleminden kurtulamazsınız. Her gün yeni bir sunucuyu devreye sokmayı göze alabiliyorsanız, sorunlarınızın artık belirli bir veritabanı düzleminde yer almayacağı açıktır.

"Donanımda" bölümlemeyi uygulamak için belirli komut dosyalarını değil, yaklaşımın kendisini - neyin ve nasıl "dilimlere ayrılması" gerektiğini ve böyle bir arzunun neye yol açtığını ele alacağız.

kavram

Amacımızı bir kez daha tanımlayalım: Bugün, yarın ve bir yıl içinde herhangi bir okuma/yazma işlemi sırasında PostgreSQL tarafından okunan veri miktarının yaklaşık olarak aynı kalmasını sağlamak istiyoruz.

Herhangi kronolojik olarak toplanan veriler (mesajlar, belgeler, günlükler, arşivler, ...) bölümleme anahtarı olarak doğal seçim etkinlik tarihi/saati. Bizim durumumuzda böyle bir olay mesajın gönderilme anı.

Kullanıcıların neredeyse her zaman yalnızca “en yeni” olanlarla çalışın bu tür veriler - en son mesajları okurlar, en son kayıtları analiz ederler,... Hayır, elbette zamanda daha geriye gidebilirler, ancak bunu çok nadiren yaparlar.

Bu kısıtlamalardan, en uygun mesaj çözümünün şu olacağı açıktır: "günlük" bölümler - sonuçta kullanıcımız neredeyse her zaman kendisine "bugün" veya "dün" gelenleri okuyacaktır.

Gün içinde neredeyse sadece tek bir bölümde yazıp okuyorsak, bu da bize şunu kazandırır: belleğin ve diskin daha verimli kullanılması - tablodaki "büyük ve şişman" indekslerin aksine, tüm bölüm indeksleri RAM'e kolayca sığdığından.

adım adım

Genel olarak yukarıda söylenen her şey, sürekli bir kâr gibi geliyor. Ve bu başarılabilir, ancak bunun için çok denememiz gerekecek - çünkü kuruluşlardan birini bölme kararı, ilgili birimin "görülmesi" ihtiyacına yol açar.

Mesaj, özellikleri ve projeksiyonları

İletileri tarihlere göre kesmeye karar verdiğimiz için, onlara bağlı olan varlık özelliklerini (ekli dosyalar, alıcı listesi) ve ayrıca mesaj tarihine göre.

Tipik görevlerimizden biri mesaj kayıtlarını (okunmamış, gelen, tümü) tam olarak görüntülemek olduğundan, bunları mesaj tarihlerine göre bölümlemeye "dahil etmek" de mantıklıdır.

Messenger veritabanı (bölüm 2): "kâr amaçlı" bölümlendirme

Bölümleme anahtarını (mesaj tarihi) tüm tablolara ekliyoruz: alıcılar, dosya, kayıtlar. Bunu mesajın kendisine eklemeniz gerekmez, ancak mevcut DateTime'ı kullanın.

ipler

Birkaç mesaj için tek bir konu olduğundan, onu aynı modelde "kesmenin" bir yolu yoktur; başka bir şeye güvenmeniz gerekir. Bizim durumumuzda ideal yazışmalardaki ilk mesajın tarihi - yani konunun yaratılma anı.

Messenger veritabanı (bölüm 2): "kâr amaçlı" bölümlendirme

Bölümleme anahtarını (konu tarihi) tüm tablolara ekleyin: konu, katılımcı.

Ama şimdi aynı anda iki sorunumuz var:

  • Konuyla ilgili mesajları hangi bölümde aramalıyım?
  • Mesajdaki konuyu hangi bölümde aramalıyım?

Elbette tüm bölümlerde aramaya devam edebiliriz ancak bu çok üzücü olacak ve tüm kazancımızı boşa çıkaracaktır. Bu nedenle, tam olarak nereye bakacağımızı bilmek için bölümlere mantıksal bağlantılar/işaretçiler yapacağız:

  • mesaja ekleyeceğiz konu tarih alanı
  • konuya ekleyelim mesaj tarihi ayarlandı bu yazışma (ayrı bir tablo veya bir tarih dizisi olabilir)

Messenger veritabanı (bölüm 2): "kâr amaçlı" bölümlendirme

Her bir yazışma için mesaj tarihleri ​​listesinde çok az değişiklik olacağından (sonuçta neredeyse tüm mesajlar birbirini takip eden 1-2 güne denk geliyor), bu seçeneğe odaklanacağım.

Toplamda, veri tabanımızın yapısı, bölümlendirme dikkate alınarak aşağıdaki formu almıştır:

Tablolar: RU, eğer tablo/alan adlarında Kiril alfabesinden hoşlanmıyorsanız, tablo/alan adlarına bakmamak daha iyidir.

-- секции по дате сообщения
CREATE TABLE "Сообщение_YYYYMMDD"(
  "Сообщение"
    uuid
      PRIMARY KEY
, "Тема"
    uuid
, "ДатаТемы"
    date
, "Автор"
    uuid
, "ДатаВремя" -- используем как дату
    timestamp
, "Текст"
    text
);

CREATE TABLE "Адресат_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Сообщение"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Сообщение", "Персона")
);

CREATE TABLE "Файл_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Файл"
    uuid
      PRIMARY KEY
, "Сообщение"
    uuid
, "BLOB"
    uuid
, "Имя"
    text
);

CREATE TABLE "РеестрСообщений_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Владелец"
    uuid
, "ТипРеестра"
    smallint
, "ДатаВремя"
    timestamp
, "Сообщение"
    uuid
, PRIMARY KEY("Владелец", "ТипРеестра", "Сообщение")
);
CREATE INDEX ON "РеестрСообщений_YYYYMMDD"("Владелец", "ТипРеестра", "ДатаВремя" DESC);

-- секции по дате темы
CREATE TABLE "Тема_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
      PRIMARY KEY
, "Документ"
    uuid
, "Название"
    text
);

CREATE TABLE "УчастникТемы_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Тема", "Персона")
);

CREATE TABLE "ДатыСообщенийТемы_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
      PRIMARY KEY
, "Дата"
    date
);

Güzel bir kuruş tasarruf edin

Peki ya kullanmazsak klasik kesit seçeneği alan değerlerinin dağıtımına (tetikleyiciler ve miras yoluyla veya PARTITION BY aracılığıyla) ve uygulama düzeyinde "manuel olarak" bağlı olarak, bölümleme anahtarının değerinin zaten tablonun adında saklandığını fark edeceksiniz.

Yani eğer öyleysen Depolanan veri miktarı konusunda çok endişeli misiniz?, o zaman bu “ekstra” alanlardan kurtulabilir ve belirli tabloları adresleyebilirsiniz. Doğru, bu durumda birkaç bölümden yapılan tüm seçimlerin uygulama tarafına aktarılması gerekecektir.

Kaynak: habr.com

Yorum ekle