Topik ini menjelaskan fitur pembagian dan pengelompokan ApsaraDB for SelectDB serta cara menggunakan partisi dan bucket di ApsaraDB for SelectDB.
Ikhtisar
Untuk menyimpan dan menghitung sejumlah besar data secara efisien, ApsaraDB for SelectDB membagi data berdasarkan partisi dan mendistribusikan data ke sistem terdistribusi untuk diproses.
Semua model data yang didukung oleh ApsaraDB for SelectDB mendukung pembagian data pada dua tingkat berikut:
Satu tingkat: Data dibagi hanya pada satu tingkat.
Saat Anda membuat tabel, Anda tidak perlu menulis pernyataan untuk membagi data. Dalam hal ini, ApsaraDB for SelectDB membuat partisi default yang transparan bagi Anda. Jika Anda membagi data pada satu tingkat, hanya pengelompokan yang didukung.
Dua tingkat: Data dibagi pada dua tingkat.
Tingkat pertama adalah partisi, yang mendukung pembagian rentang dan pembagian daftar.
Tingkat kedua adalah bucket, juga dikenal sebagai tablet, yang mendukung pembagian hash.
Pembagian
Partisi digunakan untuk membagi data ke dalam rentang yang berbeda. Ini mirip dengan membagi tabel menjadi beberapa tabel anak. Dengan cara ini, Anda dapat mengelola data di partisi. Saat menggunakan partisi, perhatikan hal-hal berikut:
Anda dapat menentukan satu atau lebih kolom sebagai kolom kunci partisi. Kolom kunci partisi harus berupa kolom kunci.
Anda harus mengapit nilai kunci partisi dalam tanda kutip ganda (") terlepas dari jenis kolom kunci partisi.
Jumlah partisi yang dapat Anda buat secara teoritis tidak terbatas.
Jika Anda membuat tabel tanpa menentukan partisi, sistem secara otomatis membuat partisi yang namanya sama dengan tabel dan berisi seluruh data tabel. Partisi ini tidak terlihat bagi Anda dan tidak dapat dihapus atau dimodifikasi.
Saat Anda membuat partisi, rentang partisi tidak boleh tumpang tindih dengan partisi lainnya.
Pembagian rentang
Dalam banyak kasus, kolom waktu digunakan sebagai kolom kunci partisi selama pembagian rentang untuk memudahkan pengelolaan data baru dan historis. Rentang partisi memungkinkan Anda menentukan hanya batas atas dengan menjalankan pernyataan VALUES LESS THAN (...). Sistem menggunakan batas atas partisi sebelumnya sebagai batas bawah partisi saat ini untuk membuat partisi dengan rentang tertutup kiri dan terbuka kanan. Anda juga dapat menentukan batas atas dan bawah dengan menjalankan pernyataan VALUES [...] untuk membuat partisi dengan rentang tertutup kiri dan terbuka kanan.
Pembagian kolom tunggal
Bagian ini menjelaskan bagaimana rentang partisi tabel berubah jika Anda menjalankan pernyataan VALUES LESS THAN (...) untuk membuat atau menghapus partisi untuk tabel. Contoh kode berikut memberikan contoh:
Buat tabel bernama
test_table.CREATE TABLE IF NOT EXISTS test_db.test_table ( `user_id` LARGEINT NOT NULL COMMENT "ID pengguna", `date` DATE NOT NULL COMMENT "Tanggal ketika data diimpor ke tabel", `timestamp` DATETIME NOT NULL COMMENT "Waktu ketika data diimpor ke tabel", `city` VARCHAR(20) COMMENT "Kota tempat pengguna tinggal", `age` SMALLINT COMMENT "Usia pengguna", `sex` TINYINT COMMENT "Jenis kelamin pengguna", `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "Waktu terakhir pengguna berkunjung", `cost` BIGINT SUM DEFAULT "0" COMMENT "Jumlah uang yang dibelanjakan pengguna", `max_dwell_time` INT MAX DEFAULT "0" COMMENT "Waktu tinggal maksimum pengguna", `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "Waktu tinggal minimum pengguna" )ENGINE=OLAP AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`) PARTITION BY RANGE(`date`) ( PARTITION `p201701` VALUES LESS THAN ("2017-02-01"), PARTITION `p201702` VALUES LESS THAN ("2017-03-01"), PARTITION `p201703` VALUES LESS THAN ("2017-04-01") ) DISTRIBUTED BY HASH(`user_id`) BUCKETS 16;Setelah tabel
test_tabledibuat, tiga partisi berikut secara otomatis dibuat:p201701: [MIN_VALUE, 2017-02-01) p201702: [2017-02-01, 2017-03-01) p201703: [2017-03-01, 2017-04-01)Jalankan pernyataan
ALTER TABLE test_db.test_table ADD PARTITION p201705 VALUES LESS THAN ("2017-06-01");untuk membuat partisi bernamap201705. Contoh kode berikut menunjukkan hasil pembagian:p201701: [MIN_VALUE, 2017-02-01) p201702: [2017-02-01, 2017-03-01) p201703: [2017-03-01, 2017-04-01) p201705: [2017-04-01, 2017-06-01)Jalankan pernyataan
ALTER TABLE test_db.test_table DROP PARTITION p201703;untuk menghapus partisip201703. Contoh kode berikut menunjukkan hasil pembagian:p201701: [MIN_VALUE, 2017-02-01) p201702: [2017-02-01, 2017-03-01) p201705: [2017-04-01, 2017-06-01)PentingDalam contoh sebelumnya, setelah partisi
p201703dihapus, rentang partisip201702danp201705tetap tidak berubah. Namun, rentang [2017-03-01, 2017-04-01) antara dua rentang tersebut kosong. Data yang ada dalam rentang ini juga dihapus. Dalam hal ini, jika data yang akan diimpor berada dalam rentang kosong, data tidak dapat diimpor.Hapus partisi
p201702. Contoh kode berikut menunjukkan hasil pembagian:p201701: [MIN_VALUE, 2017-02-01) p201705: [2017-04-01, 2017-06-01)Rentang kosong menjadi [2017-02-01, 2017-04-01).
Jalankan pernyataan
`p201702new` VALUES LESS THAN ("2017-03-01")untuk membuat partisi. Contoh kode berikut menunjukkan hasil pembagian:p201701: [MIN_VALUE, 2017-02-01) p201702new: [2017-02-01, 2017-03-01) p201705: [2017-04-01, 2017-06-01)Rentang kosong menjadi [2017-03-01, 2017-04-01).
Hapus partisi p201701 dan jalankan pernyataan
`p201612` VALUES LESS THAN ("2017-01-01")untuk membuat partisi. Contoh kode berikut menunjukkan hasil pembagian:p201612: [MIN_VALUE, 2017-01-01) p201702new: [2017-02-01, 2017-03-01) p201705: [2017-04-01, 2017-06-01)Rentang kosong menjadi [2017-01-01, 2017-02-01) dan [2017-03-01, 2017-04-01).
Contoh sebelumnya menunjukkan bahwa rentang partisi yang ada tetap tidak berubah setelah Anda menghapus partisi. Namun, rentang kosong mungkin terjadi. Jika Anda menjalankan pernyataan VALUES LESS THAN (...) untuk membuat partisi, batas bawah partisi harus bersebelahan dengan batas atas partisi sebelumnya.
Pembagian multi-kolom
Saat Anda membuat partisi untuk tabel, Anda dapat membagi data berdasarkan beberapa kolom. Contoh kode berikut memberikan contoh:
PARTITION BY RANGE(`date`, `id`)
(
PARTITION `p201701_1000` VALUES LESS THAN ("2017-02-01", "1000"),
PARTITION `p201702_2000` VALUES LESS THAN ("2017-03-01", "2000"),
PARTITION `p201703_all` VALUES LESS THAN ("2017-04-01")
)Dalam contoh ini, kolom date dan id ditentukan sebagai kolom kunci partisi. Kolom date bertipe DATE, dan kolom id bertipe INT. Contoh kode berikut menunjukkan hasil pembagian:
* p201701_1000: [(MIN_VALUE, MIN_VALUE), ("2017-02-01", "1000") )
* p201702_2000: [("2017-02-01", "1000"), ("2017-03-01", "2000") )
* p201703_all: [("2017-03-01", "2000"), ("2017-04-01", MIN_VALUE)) Di partisi terakhir, hanya nilai kolom date yang ditentukan. Secara default, MIN_VALUE digunakan sebagai nilai kolom id. Saat Anda memasukkan data, sistem membandingkan data dengan nilai kunci partisi yang ditentukan secara berurutan untuk menentukan partisi ke mana data dimasukkan. Contoh kode berikut memberikan contoh:
* Data --> Partisi
* 2017-01-01, 200 --> p201701_1000
* 2017-01-01, 2000 --> p201701_1000
* 2017-02-01, 100 --> p201701_1000
* 2017-02-01, 2000 --> p201702_2000
* 2017-02-15, 5000 --> p201702_2000
* 2017-03-01, 2000 --> p201703_all
* 2017-03-10, 1 --> p201703_all
* 2017-04-01, 1000 --> Gagal diimpor.
* 2017-05-01, 1000 --> Gagal diimpor.Pembagian daftar
Pembagian daftar mendukung kolom kunci partisi dengan tipe data berikut: BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE, DATETIME, CHAR, and VARCHAR. Nilai kunci partisi adalah nilai enumerasi. Data yang akan diimpor hanya mengenai partisi jika data tersebut berisi salah satu nilai enumerasi partisi.
Anda dapat menentukan nilai enumerasi yang terkandung dalam setiap partisi dengan menjalankan pernyataan VALUES IN (...).
Pembagian kolom tunggal
Bagian ini menjelaskan bagaimana partisi tabel berubah jika Anda menjalankan pernyataan VALUES IN (...) untuk membuat atau menghapus partisi untuk tabel. Contoh kode berikut memberikan contoh:
Buat tabel bernama
test_table1.CREATE TABLE IF NOT EXISTS test_db.example_list_tbl1 ( `user_id` LARGEINT NOT NULL COMMENT "ID pengguna", `date` DATE NOT NULL COMMENT "Tanggal ketika data diimpor ke tabel", `timestamp` DATETIME NOT NULL COMMENT "Waktu ketika data diimpor ke tabel", `city` VARCHAR(20) NOT NULL COMMENT "Kota tempat pengguna tinggal", `age` SMALLINT COMMENT "Usia pengguna", `sex` TINYINT COMMENT "Jenis kelamin pengguna", `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "Waktu terakhir pengguna berkunjung", `cost` BIGINT SUM DEFAULT "0" COMMENT "Jumlah uang yang dibelanjakan pengguna", `max_dwell_time` INT MAX DEFAULT "0" COMMENT "Waktu tinggal maksimum pengguna", `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "Waktu tinggal minimum pengguna" ) ENGINE=olap AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`) PARTITION BY LIST(`city`) ( PARTITION `p_cn` VALUES IN ("Beijing", "Shanghai", "Hong Kong"), PARTITION `p_usa` VALUES IN ("New York", "San Francisco"), PARTITION `p_jp` VALUES IN ("Tokyo") ) DISTRIBUTED BY HASH(`user_id`) BUCKETS 16;Setelah tabel
test_table1dibuat, tiga partisi berikut secara otomatis dibuat:p_cn: ("Beijing", "Shanghai", "Hong Kong") p_usa: ("New York", "San Francisco") p_jp: ("Tokyo")Jalankan pernyataan
`p_uk` VALUES IN ("London")untuk membuat partisi. Contoh kode berikut menunjukkan hasil pembagian:p_cn: ("Beijing", "Shanghai", "Hong Kong") p_usa: ("New York", "San Francisco") p_jp: ("Tokyo") p_uk: ("London")Hapus partisi
p_jp. Contoh kode berikut menunjukkan hasil pembagian:p_cn: ("Beijing", "Shanghai", "Hong Kong") p_usa: ("New York", "San Francisco") p_uk: ("London")
Pembagian multi-kolom
Saat Anda membuat partisi untuk tabel, Anda dapat membagi data berdasarkan beberapa kolom. Contoh kode berikut memberikan contoh:
PARTITION BY LIST(`id`, `city`)
(
PARTITION `p1_city` VALUES IN (("1", "Beijing"), ("1", "Shanghai")),
PARTITION `p2_city` VALUES IN (("2", "Beijing"), ("2", "Shanghai")),
PARTITION `p3_city` VALUES IN (("3", "Beijing"), ("3", "Shanghai"))
)Dalam contoh ini, kolom id dan city ditentukan sebagai kolom kunci partisi. Kolom id bertipe INT, dan kolom city bertipe VARCHAR. Contoh kode berikut menunjukkan hasil pembagian:
* p1_city: [("1", "Beijing"), ("1", "Shanghai")]
* p2_city: [("2", "Beijing"), ("2", "Shanghai")]
* p3_city: [("3", "Beijing"), ("3", "Shanghai")]Saat Anda memasukkan data, sistem membandingkan data dengan nilai kunci partisi yang ditentukan secara berurutan untuk menentukan partisi ke mana data dimasukkan. Contoh kode berikut memberikan contoh:
* Data ---> Partisi
* 1, Beijing ---> p1_city
* 1, Shanghai ---> p1_city
* 2, Shanghai ---> p2_city
* 3, Beijing ---> p3_city
* 1, Tianjin ---> Gagal diimpor.
* 4, Beijing ---> Gagal diimpor.Pengelompokan
Data dibagi dan disimpan dalam bucket yang berbeda berdasarkan nilai hash dari kolom bucket.
Jika partisi digunakan, pernyataan
DISTRIBUTED...menjelaskan aturan untuk membagi data di setiap partisi. Jika tidak ada partisi yang digunakan, pernyataan tersebut menjelaskan aturan untuk membagi seluruh data tabel.Anda dapat menentukan beberapa kolom sebagai kolom bucket. Untuk model Aggregate atau Unique, kolom bucket harus berupa kolom kunci. Untuk model Duplicate, kolom bucket dapat berupa kolom kunci atau kolom nilai. Kolom bucket bisa sama atau berbeda dengan kolom kunci partisi.
Untuk menentukan kolom bucket, Anda harus menyeimbangkan antara throughput kueri dan konkurensi kueri.
Jika Anda menentukan beberapa kolom bucket, data akan lebih merata didistribusikan. Jika kondisi untuk kueri tidak mencakup kondisi ekuivalen untuk semua kolom bucket, sistem memindai semua bucket. Ini meningkatkan throughput kueri dan mengurangi latensi kueri. Metode ini cocok untuk skenario kueri dengan throughput tinggi dan konkurensi rendah.
Jika Anda hanya menentukan satu atau sejumlah kecil kolom bucket, sistem hanya memindai satu bucket untuk kueri titik. Dalam hal ini, jika beberapa kueri titik dilakukan secara bersamaan, sistem mungkin memindai bucket yang berbeda. Operasi I/O kueri tidak saling mempengaruhi, terutama ketika bucket yang berbeda didistribusikan pada disk yang berbeda. Oleh karena itu, metode ini cocok untuk skenario kueri titik dengan konkurensi tinggi.
Jumlah bucket yang dapat Anda buat secara teoritis tidak terbatas.
Praktik terbaik
Saran untuk mengonfigurasi partisi dan bucket
Jumlah total bucket dalam sebuah tabel dihitung berdasarkan rumus berikut: Jumlah total bucket = Jumlah partisi × Jumlah bucket di setiap partisi.
Jika konfigurasi kluster tidak diubah, jumlah bucket yang direkomendasikan dalam partisi tabel dapat sedikit lebih besar daripada jumlah total disk di kluster.
Secara teori, jumlah data yang dapat disimpan dalam satu bucket tidak terbatas. Namun, kami merekomendasikan Anda menyimpan 1 hingga 10 GB data dalam satu bucket. Jika jumlah data yang kecil disimpan dalam satu bucket, agregasi data mungkin gagal memenuhi kebutuhan bisnis Anda dan tekanan pada manajemen metadata tinggi. Jika jumlah data yang besar disimpan dalam satu bucket, ini tidak mendukung migrasi dan pengisian ulang replika. Ini meningkatkan biaya untuk mencoba kembali operasi gagal seperti perubahan skema atau rollup karena operasi ini dilakukan pada tingkat bucket.
Jika Anda tidak dapat menemukan keseimbangan antara jumlah data yang disimpan dalam satu bucket dan jumlah bucket, kami merekomendasikan Anda memprioritaskan jumlah data yang disimpan.
Saat Anda membuat tabel, jumlah bucket yang sama ditentukan untuk setiap partisi. Namun, saat Anda menjalankan pernyataan
ADD PARTITIONuntuk membuat partisi secara dinamis, Anda dapat menentukan jumlah bucket di partisi baru secara terpisah. Anda dapat menggunakan fitur ini untuk menangani pengurangan atau ekspansi data.Anda tidak dapat mengubah jumlah bucket dalam partisi setelah partisi dibuat. Oleh karena itu, saat Anda menentukan jumlah bucket, Anda harus mempertimbangkan peningkatan kapasitas kluster Anda terlebih dahulu. Misalnya, kluster Anda terdiri dari tiga mesin dan setiap mesin memiliki disk. Jika jumlah bucket diatur menjadi 3 atau nilai yang lebih kecil, konkurensi tidak dapat ditingkatkan meskipun Anda menambah jumlah mesin di kluster.
Tabel berikut menjelaskan saran untuk mengonfigurasi partisi dan bucket untuk kluster yang terdiri dari 10 backend dan memiliki disk pada setiap backend.
Ukuran tabel | 500 MB | 5 GB | 50 GB | 500 GB | 5 TB |
Partisi | Tidak diperlukan partisi. | Tidak diperlukan partisi. | Tidak diperlukan partisi. | Setiap partisi berukuran 50 GB. | Setiap partisi berukuran 50 GB. |
Bucket | Tabel berisi empat hingga delapan bucket. | Tabel berisi 8 hingga 16 bucket. | Tabel berisi 32 bucket. | Setiap partisi berisi 16 hingga 32 bucket. | Setiap partisi berisi 16 hingga 32 bucket. |
Anda dapat menjalankan pernyataan SHOW DATA; untuk menanyakan ukuran tabel.
Konfigurasi dan penggunaan metode distribusi acak
Untuk data rinci yang tidak perlu diagregasi atau diperbarui, Anda dapat membuat tabel menggunakan model Duplicate dan metode distribusi acak. Contoh kode berikut memberikan contoh:
CREATE TABLE IF NOT EXISTS test.example_tbl
(
`timestamp` DATETIME NOT NULL COMMENT "Waktu ketika log dihasilkan",
`type` INT NOT NULL COMMENT "Jenis log",
`error_code` INT COMMENT "Kode kesalahan",
`error_msg` VARCHAR(1024) COMMENT "Pesan kesalahan",
`op_id` BIGINT COMMENT "ID pemilik",
`op_time` DATETIME COMMENT "Waktu ketika kesalahan ditangani"
)
DUPLICATE KEY(`timestamp`, `type`, `error_code`)
DISTRIBUTED BY RANDOM BUCKETS 16;Tabel yang menggunakan model Duplicate tidak berisi kolom yang jenis agregasinya adalah REPLACE. Anda dapat mengatur mode pengelompokan data tabel ke RANDOM. Ini mencegah skew data yang serius. Saat Anda mengimpor data ke tabel, pekerjaan impor tunggal menulis data ke bucket acak dari partisi.
Jika Anda mengatur mode pengelompokan data ke RANDOM untuk tabel, Anda tidak dapat menanyakan hanya bucket tertentu berdasarkan nilai kolom bucket karena tidak ada kolom bucket yang ditentukan. Saat Anda menanyakan tabel, sistem memindai semua bucket partisi yang kueri tersebut tembus. Pengaturan ini cocok untuk kueri agregat dan analisis data lengkap tabel alih-alih kueri titik dengan konkurensi tinggi.
Jika tabel yang menggunakan model Duplicate menggunakan metode distribusi acak, Anda dapat mengaktifkan mode impor single-bucket saat mengimpor data. Untuk mengaktifkan mode impor single-bucket, atur parameter
load_to_single_tabletke true. Secara default, parameter ini diatur ke false. Dalam hal ini, saat Anda mengimpor sejumlah besar data, pekerjaan menulis data hanya ke satu bucket dari partisi. Ini dapat meningkatkan konkurensi dan throughput impor data, mengurangi masalah amplifikasi tulis yang disebabkan oleh impor data dan kompaksi, dan memastikan stabilitas kluster Anda.
Skenario di mana partisi dan bucket digunakan bersama
Jika tabel berisi kolom dimensi waktu atau kolom dimensi yang memiliki nilai terurut, kolom dimensi tersebut dapat digunakan sebagai kolom kunci partisi. Granularitas berdasarkan mana data dibagi dapat dievaluasi berdasarkan frekuensi impor dan jumlah data yang akan disimpan di setiap partisi.
Jika Anda ingin menghapus data historis untuk menyimpan hanya data dalam N hari terakhir, Anda dapat menggunakan pembagian majemuk untuk menghapus partisi historis. Atau, Anda dapat menjalankan pernyataan DELETE untuk menghapus data di partisi tertentu.
Untuk mencegah skew data, Anda dapat menentukan jumlah bucket secara terpisah untuk setiap partisi. Misalnya, dalam skenario di mana data dibagi berdasarkan hari, jika jumlah data sangat bervariasi setiap hari, Anda dapat menyesuaikan jumlah bucket untuk setiap partisi. Kami merekomendasikan Anda menentukan kolom bucket yang mudah diidentifikasi dan berdasarkan mana data dapat didistribusikan secara merata.