Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
26
Help us understand the problem. What is going on with this article?
@qantasmz

Firebaseでindexを貼るとどのくらいソートが速くなるのか

More than 3 years have passed since last update.

データベースに入っている要素を何かの数値でソートして取得したりしたくなることはすごくよくあります。
そういうことをMySQLとかでやる場合、その要素にindexというものを貼って、ソートを高速化したりするものですが、FirebaseでなんちゃってDB操作を楽しんでいるフロントエンドの人(私もそんなのですが)は、そういうのよく知りません。
しかし、Firebaseにもindex機能はちゃんとあって、しかも結構いい感じなのですが、あんまりこのあたりのことを書いている日本語文献が無かったので書いてみます。

とりあえず、indexによる高速化を実感するためにはそれなりの量のデータが必要かと思うので、jsで下記のようなコードを書いて、なんかオブジェクトを20000個くらいつくります。

bigdata.js
var MAX_NUM = 20000;
for(var i=0; i<MAX_NUM; i++){
    //各オブジェクトの名前を適当にランダムで生成
    var _name = Math.random().toString(36).slice(-16);
    //数値をランダムで生成
    var _num = Math.floor(Math.random()*1000000);

    //追加するオブジェクトのデータを用意する
    var postData = {
        name: _name,
        num: _num
    };
    //オブジェクトを追加する
    var newPostKey = firebase.database().ref().child('Objects').push().key;
    var updates = {};
    updates['/Objects/' + newPostKey] = postData;
    firebase.database().ref().update(updates, function(error) {
        if (!error) {
            _firebase.raiseEvent('dataIncreaseComplete',[]);
        }
    });
}

こんな感じのコードを実行すると、下記のような感じで大量でランダムな数値がくっついたデータが生成されます。これで準備完了です。

スクリーンショット 2016-12-22 15.17.43.png

データを取得するクライアント側は何で書いても良いのですが、今回は、Objective-Cで実験します。

下記の手順でセッティングをしつつ、
Firebase を iOS プロジェクトに追加する

podは、

pod 'Firebase/Core'
pod 'Firebase/Database'

の2つを仕込んでおきます。

そして、まず、indexとか何にも設定しないで下記を走らせてみます。
この時点のruleは下記のような感じです。

{
    "rules": {
        "Objects": {
            ".read": true,
            ".write": true
        }
    }
}

オブジェクト数は20,000個。最初の500個だけを取ってきます。

ViewController.m
#import "ViewController.h"
@import Firebase;
@import FirebaseDatabase;

@interface ViewController ()

@end

@implementation ViewController{
    FIRDatabaseReference *rootRef;
    NSDate *startDate;
    NSDate *endDate;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    rootRef= [[FIRDatabase database] reference];
    // Do any additional setup after loading the view, typically from a nib.
    FIRDatabaseReference *objects = [rootRef child: @"Objects"];

    startDate = [NSDate date];

    [[objects queryOrderedByChild:@"num"] queryLimitedToFirst:500] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot){

        endDate = [NSDate date];
        NSTimeInterval interval = [endDate timeIntervalSinceDate:startDate];
        NSLog([NSString stringWithFormat:@"処理時間 : ミリ秒 : %f",interval]);
        //データの中身を確認する場合、下記を実行
        /*
        for (FIRDataSnapshot* childSnap in snapshot.children) {
            NSLog(@"%@", childSnap.value[@"name"]);
            NSLog(@"%@", childSnap.value[@"num"]);
        }
        */
    }withCancelBlock:^(NSError *error){
    }];

}

- (NSString*)getDateString:(NSDate*)date
{
    NSDateFormatter *dateFormatter = [NSDateFormatter new];
    [dateFormatter setDateFormat:@"yyyy/MM/dd HH:mm:ss.SSS"];
    NSString *dateString = [dateFormatter stringFromDate:date];
    return dateString;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}


@end

時間計測するやつは、こちらからお借りしました。
5.973116秒で処理が終わりました。何回やってもこのあたり。
ログで内容を確認すると、ちゃんとnumが小さいやつから順番に書き出されていますが、それなりに遅いです。

というわけで、今度はindexを貼ったらどれだけ速くなるのかをやってみます。

今回は"num"の値でソートするので、Firebaseのコンソールから、ruleを下記みたいな感じにします。

{
    "rules": {
        "Objects": {
            ".read": true,
            ".write": true,
            ".indexOn": ["num"]
        }
    }
}

これだけで、"num"に対するindexが貼られました。
クライアント側のコードは変えなくて良いです。
これで再度Firebaseのレスポンスを計測してみます。

0.659976秒。すばらしい。速いです。

indexという概念は、データベースを普段から触っている人には当たり前の概念ですが、特にFirebaseはバックエンドのことあんまりよくわからなくてもフロントのノリでどうにかするための仕組みなので、結構知らない人が多いのではないかと思います。
とはいえ、改めて試してみたらわかりやすく高速だったので、こういうことをする際は、indexを貼らない手はないかと思いました。

コードは下記です。

データ増殖するやつ
Firebase-dataIncrement

iOS-app
Firebase-indextest

26
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
26
Help us understand the problem. What is going on with this article?