Strategi Filtering DynamoDB
"Filtering" di DynamoDB berarti empat hal berbeda yang memakai kata yang sama.
Tiga mempersempit data sebelum ia dibaca dan ditagih; satu — yang bernama
Filter — mempersempitnya setelah. Mengetahui mana yang mana adalah sebagian
besar keahliannya.
Bagaimana cara kerja filtering di DynamoDB?
DynamoDB punya empat cara untuk memfilter, dan hanya satu yang berjalan setelah Anda ditagih. Partition key memilih sebuah partition, sort key mempersempit sebuah potongan, dan sparse index memfilter berdasarkan kehadiran atribut — ketiganya memangkas biaya baca Anda sebelum penagihan. Sebuah FilterExpression berjalan setelah pembacaan, jadi ia mengecilkan respons tapi tak pernah tagihan.
- Partition key adalah filter termurah: ia memilih partition, jadi Anda tak pernah menyentuh sisa tabel.
- Sort key memfilter di dalam sebuah partition dengan
begins_with,between,<,>— masih sebelum penagihan, masih murah. - Sparse index memfilter berdasarkan ketiadaan: sebuah item hanya muncul di indeks jika ia punya atribut terindeks, jadi indeks adalah himpunan terfilter.
FilterExpressionadalah jebakannya: ia berjalan setelah DynamoDB mengukur pembacaan, jadi ia memangkas ukuran respons Anda tapi tak pernah tagihan Anda.
Siapkan contohnya
Sebuah katalog produk. Satu tabel, partition key PK, sort key SK:
PK = "DEPT#kitchen" SK = "PROD#00194"
Setiap produk juga membawa price, inStock (sebuah boolean), dan clearanceAt
(sebuah unix timestamp, hadir hanya pada item yang ditandai untuk clearance).
Item dalam sebuah departemen berbagi sebuah partition, terurut berdasarkan id
produk.
Kita mau empat pola akses. Masing-masing memetakan ke strategi filtering yang
berbeda — dan pilihan yang salah pada salah satunya adalah sebuah Scan yang
akan Anda bayar selamanya.
Filter berdasarkan partition key
"Beri saya setiap produk di kitchen." Partition key menjawab ini secara
langsung:
Query PK = "DEPT#kitchen"
DynamoDB membaca persis satu partition. Tak ada hal lain di tabel yang disentuh
atau ditagih. Ini adalah satu-satunya filter yang gratis dalam arti yang penting —
itulah perbedaan antara Query dan Scan.
Datang dari SQL, ini terasa terbalik: tidak ada WHERE department = 'kitchen'
yang men-scan sebuah indeks, Anda cukup menyebut partition-nya. Jika Anda tak
bisa menyebutnya, itu adalah masalah pemodelan, bukan masalah query.
Filter berdasarkan sort key
"Beri saya produk kitchen dari PROD#00100 ke atas." Sort key mempersempit di
dalam partition, dan ia melakukannya sebelum pembacaan diukur:
Query PK = "DEPT#kitchen" AND SK between "PROD#00100" AND "PROD#00200"
Kondisi sort-key terbatas dengan sengaja: =, <, <=, >, >=, between,
dan begins_with. Tanpa OR, tanpa predikat arbitrer.
Batasan itulah yang menjaga pembacaan tetap tertarget — DynamoDB menelusuri sebuah potongan yang berdampingan, bukan seluruh partition.
Tuasnya di sini adalah bagaimana Anda meng-encode sort key. Jika pola Anda
adalah "berdasarkan pita harga", sebuah sort key PROD#<id> tak akan membantu —
Anda akan memanggang harga ke dalam key.
Itu adalah keputusan strategi sort-key, dibuat saat desain, bukan saat query.
Filter berdasarkan sparse index
"Beri saya semua yang sedang clearance." Sebagian besar produk tidak, jadi Anda tak mau membaca katalog untuk menemukan yang sedikit itu.
Sebuah sparse index memecahkan ini lewat ketiadaan. Sebuah Global Secondary Index hanya berisi sebuah item jika item itu punya kedua atribut key indeksnya.
Set partition key GSI ke clearanceAt — hadir hanya pada item clearance — dan
indeks tak menampung apa pun lainnya.
AWS menjabarkan ini: sebuah GSI "hanya berisi item yang punya atribut terindeks," jadi item yang kekurangan atribut key cukup tidak dipropagasikan (AWS — Take advantage of sparse indexes).
Kini query hanya membaca item clearance, ditagih hanya untuk mereka:
Query ON ClearanceIndex GSI_PK = "CLEARANCE" (sorted by clearanceAt)
Filter terjadi saat Anda menulis datanya — dengan memilih apakah mengatur
clearanceAt sama sekali. Indeks adalah himpunan terfilter. Lihat GSI vs
LSI untuk tipe indeks mana yang cocok.
Filter dengan FilterExpression
"Beri saya produk kitchen yang in stock." inStock bukan atribut key, jadi Anda
menjangkau sebuah FilterExpression:
Query PK = "DEPT#kitchen"
Filter inStock = true
Inilah jebakannya. DynamoDB membaca setiap item di partition kitchen,
mengukur kapasitas untuk semuanya, lalu membuang yang out-of-stock.
Aturan resminya: sebuah filter expression "diterapkan setelah sebuah Query
selesai, tapi sebelum hasilnya dikembalikan," dan "tidak mengonsumsi read
capacity unit tambahan apa pun" — Anda sudah membayar untuk pembacaan penuh
(AWS — Filter expressions for Query).
Jadi jika kitchen punya 10.000 produk dan 12 in stock, Anda membayar untuk
membaca 10.000. Responsnya kecil; tagihannya tidak. FilterExpression mengecilkan
payload yang melintasi kabel, tak pernah pembacaannya.
Ada tepi kedua yang lebih tajam: paginasi diukur sebelum filtering. Sebuah halaman adalah 1 MB item yang dibaca, bukan 1 MB kecocokan.
Sebuah filter bisa mengembalikan halaman kosong dengan LastEvaluatedKey terset —
DynamoDB membaca satu megabyte penuh, tak mencocokkan apa pun, menyerahkan Anda
sebuah array kosong. Anda terus memaginasi, dan Anda membayar setiap halaman
kosong.
Bangun ekspresinya — nama, nilai, dan escaping reserved-word yang benar — dengan
DynamoDB Expression Builder agar placeholder
#inStock/:val benar pada percobaan pertama.
Bandingkan keempatnya
| Kapan ia memfilter | Memangkas biaya baca? | Daya predikat | Biaya pengaturan | |
|---|---|---|---|---|
| Partition key | Sebelum baca | Ya — satu partition | Kesamaan saja | Gratis (ia adalah key) |
| Sort key | Sebelum baca | Ya — sepotong | Rentang / begins_with | Desain sort-key |
| Sparse index | Sebelum baca | Ya — indeks-saja | Kehadiran sebuah atribut | GSI ekstra + biaya tulis |
| FilterExpression | Setelah baca | Tidak | Hampir kondisi apa pun | Tidak ada |
Baca tabelnya dari atas ke bawah: daya predikat naik, kendali biaya turun.
FilterExpression bisa mengekspresikan apa pun secara presisi justru karena ia
berjalan pada item yang sudah dibaca — itu alasan yang sama mengapa ia tak bisa
menghemat uang Anda.
Lihat di DynoTable
Saat Anda menjalankan sebuah Query dengan filter, jarak antara item yang
dibaca dan item yang dikembalikan adalah seluruh ceritanya. DynoTable
memunculkan kapasitas konsumsi di samping jumlah hasil — jadi sebuah filter yang
diam-diam membaca seluruh partition terlihat, bukan bersembunyi di tagihan bulanan
Anda.
Untuk pertanyaan lintas-item sejati yang tak bisa dijawab sebuah filter — "harga
rata-rata per departemen", "produk in stock di-join ke ulasannya" — SQL Workbench
DynoTable menjalankan GROUP BY, JOIN, dan agregasi di sisi klien atas
himpunan hasil yang terbatas, alih-alih mengompilasi ke sebuah Scan seluruh
tabel.
Jebakan dan langkah berikutnya
- Jangan pakai
FilterExpressionsebagai jalur akses utama Anda. Jika sebuah pola umum, modelkan ia ke sebuah key atau sparse index. Sebuah filter untuk bagian penyempitan terakhir yang kecil, bukan untuk sebagian besarnya. - Awasi halaman kosong. Sebuah query yang difilter bisa memaginasi lama
sambil mengembalikan apa-apa. Hormati
LastEvaluatedKey; jangan asumsikan halaman kosong berarti "selesai". - Sebuah sparse index tidak gratis. Ia memakan write capacity dan penyimpanan untuk setiap item yang mendarat di dalamnya — murah saat atributnya langka, kurang begitu saat tidak.
Estimasikan apa yang sebuah pembacaan terfilter sebenarnya akan biayai dengan kalkulator kapasitas, dan coba DynoTable untuk mengamati kapasitas konsumsi terhadap baris yang dikembalikan pada tabel Anda sendiri.