it-swarm.asia

Bagaimana cara mendesain database untuk menyimpan daftar yang disortir?

Saya mencari untuk menyimpan daftar yang diurutkan di dalam database. Saya ingin melakukan operasi berikut secara efisien.

  1. Sisipkan (x) - Sisipkan catatan x ke dalam tabel
  2. Delete (x) - Hapus record x dari tabel
  3. Sebelum (x, n) - Mengembalikan catatan 'n' sebelum catatan x dalam daftar yang diurutkan.
  4. After (x, n) - Mengembalikan catatan 'n' yang menggantikan catatan x dalam daftar yang diurutkan.
  5. First (n) - Mengembalikan catatan 'n' pertama dari daftar yang diurutkan.
  6. Terakhir (n) - Mengembalikan catatan 'n' terakhir dari daftar yang diurutkan.
  7. Bandingkan (x, y) - Diberikan dua catatan x dan y dari tabel, cari apakah x> y.

Metode sederhana yang bisa saya pikirkan adalah untuk menyimpan semacam atribut 'peringkat' dalam tabel dan permintaan dengan menyortir atribut itu. Tetapi dalam metode ini memasukkan/memodifikasi catatan dengan peringkat menjadi operasi yang mahal. Apakah ada metode yang lebih baik?

Secara khusus, saya ingin mengimplementasikan tabel menggunakan SimpleDB Amazon. Tetapi jawaban umum untuk database relasional juga harus membantu.

Perbarui profil yang dimuat:

Karena saya merencanakan ini untuk aplikasi web, itu tergantung pada jumlah pengguna yang menggunakan aplikasi.

Jika ada 100k pengguna aktif (super optimisme: P), maka perkiraan saya yang sangat per hari akan menjadi

500k memilih, 100k menyisipkan dan menghapus, pembaruan 500k

Saya berharap meja tumbuh total hingga 500 ribu.

Saya mencari untuk mengoptimalkan pada pembaruan, masukkan dan operasi Bandingkan. Peringkat item akan terus berubah dan saya harus terus memperbarui tabel.

44
chitti

Jika peringkat tidak sepenuhnya sewenang-wenang tetapi sebaliknya berasal dari beberapa properti lain (mis. Nama, skor pemain, dll.) Maka perhatikan baik-baik --- jawaban Joel .

Jika adalah properti sewenang-wenang dari data Anda, maka itu harus disimpan sebagai kolom dalam tabel catatan Anda. Dengan asumsi SimpleDB Amazon mirip dengan RDBMS biasa, Anda kemudian dapat mengindeks kolom ini dan dengan cepat memenuhi semua pertanyaan Anda di atas dengan strategi pengindeksan yang sesuai. Ini normal untuk RDBMS.

Mengingat Anda mengharapkan aktivitas memasukkan dan memperbarui tinggi, tetapi juga aktivitas membaca relatif tinggi, saya sarankan melakukan hal berikut:

  • Klasterkan tabel di peringkat, terutama jika sebagian besar pertanyaan Anda menentang peringkat. Jika tidak, atau jika memilih kunci pengelompokan tidak tersedia di SimpleDB, maka cukup buat indeks dengan peringkat sebagai kolom utama. Ini akan memuaskan kueri 3-6.
  • Indeks pada catatan pertama dan kemudian peringkat (atau, di dunia SQL Server, hanya merekam dan INCLUDE - ing peringkat, atau hanya mencatat jika Anda sudah mengelompokkan pada peringkat) akan memenuhi permintaan 7.
  • Operasi 1 dan 2 dapat dioptimalkan dengan membuat spasi data Anda secara tepat (mis., Mengatur FILLFACTOR di SQL Server). Ini sangat penting jika Anda mengelompokkan berdasarkan peringkat.
  • Saat Anda menyisipkan atau memperbarui peringkat, pertahankan sebanyak mungkin kesenjangan antara jumlah peringkat untuk meminimalkan kemungkinan bahwa Anda perlu menentukan peringkat ulang catatan yang ada untuk mengakomodasi penyisipan atau pembaruan peringkat. Misalnya, jika Anda memberi peringkat catatan Anda dalam langkah-langkah 1000, Anda meninggalkan ruang yang cukup untuk sekitar setengah dari banyak perubahan dan menyisipkan dengan peluang minimal Anda harus menentukan peringkat catatan yang tidak terlibat langsung dalam perubahan itu.
  • Setiap malam ulang peringkat semua catatan untuk mengatur ulang kesenjangan peringkat di antara mereka.
  • Anda dapat menyetel frekuensi peringkat ulang massal serta ukuran kesenjangan peringkat untuk mengakomodasi jumlah insert atau pembaruan yang Anda harapkan relatif terhadap jumlah catatan yang ada. Jadi, jika Anda memiliki catatan 100 ribu dan mengharapkan sisipan dan pembaruan Anda menjadi 10% dari itu, sisakan ruang yang cukup untuk 10 ribu peringkat baru dan ulang peringkat malam.
  • Merangking ulang rekam 500 ribu adalah operasi yang mahal, tetapi dilakukan sekali sehari atau seminggu di luar jam kerja harus baik untuk database seperti itu. Pemeringkatan ulang di luar jam ini untuk menjaga kesenjangan peringkat adalah apa yang menyelamatkan Anda karena harus menentukan peringkat ulang banyak catatan untuk setiap pembaruan peringkat atau menyisipkan selama jam normal dan puncak Anda.

Jika Anda mengharapkan 100K + membaca di tabel berukuran 100K + saya tidak merekomendasikan menggunakan pendekatan daftar tertaut. Itu tidak akan skala dengan baik untuk ukuran-ukuran itu.

22
Nick Chammas

Saya biasanya menggunakan metode "peringkat" yang Anda jelaskan. Daripada main-main dengan memperbarui baris ketika item perlu dipesan ulang saya sering bisa lolos dengan menghapus semua catatan dalam daftar dan memasukkan kembali item baru dalam urutan yang tepat. Metode ini jelas dioptimalkan untuk pengambilan.

Pendekatan alternatif adalah memodelkan catatan sebagai daftar tertaut dengan menggunakan kolom kunci asing refleksif "pendahulu" pada tabel:

ID   setID   item       predecessor
---  ------  ------     ------------
1    1       Apple      null
2    1       Orange     1
3    2       Cucumber   null
4    1       Pear       2
5    1       Grape      4
6    2       Carrot     3

Anda dapat dengan mudah mengambil daftar dan menambah dan menghapus item dengan sedikit overhead, tetapi mengeluarkan catatan dalam urutan yang tepat akan sulit. Mungkin ada cara cerdas untuk melakukannya dalam satu permintaan, mungkin dengan banyak gabungan tabel alias.

Saya menggunakan pendekatan terakhir ini sering ketika saya memodelkan hubungan gaya pohon (kategori, folder, set dan himpunan bagian). Saya biasanya memiliki fungsi rekursif semacam untuk merekonstruksi pohon lengkap dalam aplikasi saya.

13
bpanulla

Saya akan berpikir hal yang harus dilakukan adalah menyimpan properti atau properti yang digunakan untuk menghitung peringkat dan kemudian membangun indeks di atasnya. Daripada mencoba memaksa database untuk secara fisik menyimpan data dalam urutan peringkat atau menggunakan daftar tertaut yang dikelola secara manual, mengapa tidak membiarkan mesin database melakukan apa yang dirancang untuk dilakukan?

6
Joel Brown

Ini adalah keterbatasan non-RDBMS seperti simpleDB. Fitur yang Anda butuhkan tidak dapat diimplementasikan pada sisi DB di simpleDB, mereka harus diimplementasikan dari sisi pemrograman/aplikasi.

Untuk RDBMS seperti SQL server, fitur yang Anda butuhkan belum sempurna untuk indeks berkerumun.

  • Sisipkan (x) - Sisipkan catatan x ke tabel> Sisipkan sederhana.
  • Hapus (x) - Hapus catatan x dari tabel> Hapus sederhana.
  • Sebelum (x, n) - Mengembalikan catatan 'n' sebelum catatan x dalam daftar yang diurutkan. > Pilih n atas hasil di mana x kurang dari nilai dan urutan dengan klausa.

  • After (x, n) - Mengembalikan catatan 'n' yang menggantikan catatan x dalam daftar yang diurutkan. > Pilih n atas hasil di mana x lebih besar dari nilai dan urutan dengan klausa.

  • First (n) - Mengembalikan catatan 'n' pertama dari daftar yang diurutkan. > Pilih n hasil atas.

  • Terakhir (n) - Mengembalikan catatan 'n' terakhir dari daftar yang diurutkan. > Pilih n atas hasil setelah pesanan oleh desc.

  • Bandingkan (x, y) - Diberikan dua catatan x dan y dari tabel, cari apakah x> y. > Pernyataan TSQL IF.
1
StanleyJohns

Inilah yang saya gunakan untuk memberi peringkat ulang tabel Postgres saya setelah setiap sisipan:

CREATE OR REPLACE FUNCTION re_rank_list() RETURNS trigger AS $re_rank_list$
DECLARE
    temprow record;
    row_idx integer := 1;    
BEGIN
    FOR temprow IN
    SELECT * FROM your_schema.your_list WHERE list_id = NEW.list_id ORDER BY rank ASC
    LOOP
        UPDATE your_schema.your_list SET rank = row_idx * 100 WHERE id = temprow.id;
        row_idx := row_idx + 1;
    END LOOP;
    RETURN NEW;
END;
$re_rank_list$ LANGUAGE plpgsql;


CREATE TRIGGER re_rank_list AFTER UPDATE ON your_schema.your_list_value
    FOR EACH ROW 
    WHEN (pg_trigger_depth() = 0)
    EXECUTE PROCEDURE re_rank_list();

Untuk kasus penggunaan saya, kinerja bukan masalah, tetapi keyakinan bahwa itu tidak akan pernah rusak atau bertindak aneh adalah penting.

0
Mark