iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 14
0
Modern Web

我或許沒那麼懂 Web系列 第 14

Cloud Firestore β (6): 索引

昨天有提到以子集合的架構與同街集合的架構,去查詢聊天室的訊息,在速度上是差不多的,但只簡單提到和索引(Index)有關,而沒詳細解釋,所以今天就來研究索引吧。

資料庫的查詢效率,通常取決於索引的建立。若是沒有建立索引,那麼資料庫系統就只能將整份清單的資料都逐一比對,這會在清單的資料筆數越來越多時,讓查詢效率越來越差。所以針對時常查詢的欄位建立索引,是在規劃資料庫必須做的事情之一。

而 Cloud Firestore 之所以查詢速度會如此快速,有一個很大的原因就在於它為文件的每個欄位都自動建立了「單欄索引」(Single-field indexes)。也就是為每個文件欄位,都建立兩個最基本的索引——升序和降序,讓我們只需要針對這個欄位去查詢、或是排序時,都能有最佳的查詢速度。

以前面的例子來說明:

users: {
  "ruoshi": {
    first : "Ruoshi"
    last : "Lin"
    born : 1900
  },
  "ironman": {
    nick : "IR"
  }
}

在 users 這個集合裡面,就有八個索引,分別是 first、last、born、nick 欄位的升降序索引。這都是 Firestore 會自動建立的,我們不用刻意去管理,就可以直接使用 <, <=, ==, >=, > 做查詢,像是這樣:

usersRef.where("first", "==", "Ruoshi")
usersRef.where("born", "<", 1950)
usersRef.where("nick", ">=", "IR")

而這個自動建立索引的範圍也包括 map 資料型別欄位裡的任何欄位,以下面的例子為例:

users: {
  "ruoshi": {
    name: {
      first : "Ruoshi"
      last : "Lin"
    }
    born : 1900
  }
}

我們可以透過這樣的方式去查詢而不用另外建立索引:

usersRef.where("name.first", "==", "Ruoshi")

但自動建立索引的對象並不是所有資料型別的欄位都通用,像是 map 型別就只會針對其底下的非 map 型別欄位建立索引,map 型別欄位本身是沒有索引的。另一個比較特殊的是 array 型別的欄位,該欄位無法像是一般欄位可以透過 <, <=, ==, >=, > 做查詢,也不會建立升降序兩個索引。但相對的,Cloud Firestore 會為它建立一個稱作 array-contains的索引,讓我們可快速查詢該 array 有沒有包含什麼值。一樣舉個例子:

users: {
  "ruoshi": {
    tags: ["abc", "xyz"]  
  }
}

可以這樣查詢:

usersRef.where("tags", "array_contains", "abc")

講解到這邊,就有另一個疑惑了,假設我要多重條件查詢時,那該怎麼辦?而 Cloud Firestore 其實還有另一種索引,叫做「複合索引」(Composite indexes),也就是讓我們能夠客製化多個條件下的索引,這部分就需要我們自己手動建立,至於為什麼不像單欄索引一樣幫忙建立呢?那是因為複合索引的組合實在太多了,而會用到的組合少之又少,效益就顯得低落。

那我們該如何建立複合索引呢?有兩種方式可以進行,第一種就是自己到 Cloud Firestore 資料庫頁面的索引分頁去建立,另一種方式就是先編寫程式進行多重條件查詢,當資料庫沒有該複合索引時,程式就會出錯,而錯誤訊息中就包含了建立該索引的懶人連結,只要點選該連結就可以到已經填好的複合索引建立表單囉。

今天大致就針對研究索引的部分簡單記錄到這邊,其實還有一些小細節沒有提到,就等到之後有時間再另外說明吧!


上一篇
Cloud Firestore β (5): 資料分層規劃
下一篇
Cloud Firestore β (7): 欄位
系列文
我或許沒那麼懂 Web31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言