Menengah7 menit baca

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.
  • FilterExpression adalah 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).

YaTidakBase table semua produkPunya clearanceAt?Direplikasi ke ClearanceIndexTidak di indeksQuery indeks = item clearancesaja

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 memfilterMemangkas biaya baca?Daya predikatBiaya pengaturan
Partition keySebelum bacaYa — satu partitionKesamaan sajaGratis (ia adalah key)
Sort keySebelum bacaYa — sepotongRentang / begins_withDesain sort-key
Sparse indexSebelum bacaYa — indeks-sajaKehadiran sebuah atributGSI ekstra + biaya tulis
FilterExpressionSetelah bacaTidakHampir kondisi apa punTidak 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 FilterExpression sebagai 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.

Diperbarui