7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CoconeAdvent Calendar 2022

Day 17

パフォーマンスを意識するロジックの書き方

Posted at

はじめに

今回は、普段の開発におけるソースレビューを通じて見つかった改善点を紹介したいと思います。

オンラインゲームやソーシャル系のアプリでは、サーバー側は常に大量のデータを扱っています。細かい修正でも積み重なると大きなパフォーマンス改善になりますので、この辺を常に意識して開発に取り組むことが大切です。

例1: 複数条件

例として、あるアイテムを所持してる場合に10%の確率で当たるという仕様の実装だと、javaではこのような感じで書きます。

List<Item> userItems = this.userItemService.findUserItemByItemId(userId, itemId);
int rand = RandUtils.nextInt(100);
if (userItems.size() > 0 && rand < 10) {
     // あたった場合のロジック
}

改善すべきところがお分かりですか?

そうです!条件に必要なデータを全て揃えるのではなく、段階的に取得したほうが効率のいい書き方になります。ちょっとだけの修正で、DBへのアクセスを90%減らすことができます。

int rand = RandUtils.nextInt(100);
if (rand < 10) {
  List<Item> userItems = this.userItemService.findUserItemByItemId(userId, itemId);
  if (userItems.size() > 0) {
     // あたった場合のロジック
  }
}

すべでの条件にはDBにアクセスが必要の場合でも、軽い処理を優先させることによってDBの負荷軽減に繋がります。

つまり、軽い処理を優先にするとのことです。

例2:データ取得その1

1つ目の例の中に、実はもう1点改善できる部分があるのですが、気づきましたか?

ユーザーが特定のアイテムを所持してるかのチェックをする際に、所持アイテムをすべて取得していました。

  List<Item> userItems = this.userItemService.findUserItemByItemId(userId, itemId);

しかし、実際は必要なアイテムだけを取得すれば問題ないため、クエリの改善を行ってみます。

  Item userItem = this.userItemService.findFirstByUserIdAndItemId(userId, itemId);

例3:データ取得その2

こちらは、他人のほしいリストを表示した時に、リスト内のアイテムを自分も持っていることを示すflagを返すための実装です。

Map allMyItems = this.service.getUserData(userId);
List<Item> pageList = this.service.fetchPagingList(friendUserId, fromNo, pageCnt);
for (Item item : pageList) {
  item.setExists(allMyItems.containKeys(item.getKey()));
}

こちらも同様に、自分の全ての所持アイテムデータを取得するよりも、1ページ分のアイテムのデータだけを取得したほうがパフォーマンスの良い実装になります。

List<Item> pageList = this.service.fetchPagingList(friendUserId, fromNo, pageCnt);
Set<Integer> itemKeys = pageList.stream().map(Item::getKey).collect(Collectors.toSet());
Map myItems = this.service.getUserDataByKeys(userId, itemKeys);
for (Item item : pageList) {
  item.setExists(allMyItems.containKeys(item.getKey()));
}

たとえDBのindexがあっても、必要な件数、必要なコラムだけを取得することでネットワークのトラフィク軽減にもつながるので、積極的そういう実装にしましょう。

例4:データ取得その3

最後に、ループ内でDBへのアクセスも可能な限りしないように実装を行いましょう。

普段はそういうことをしないと思いますが、既存のメソッドを呼んで、データを整形したり、情報を取り出したりした場合、そのメソッドの中さらにDBアクセスしてることを気づかずに行なってしまうケースが多いです。

今回は具体例は割愛しますが、ループ内でメソッドを呼び出す場合には中身をしっかりと確認したりしたほうがいいでしょう。

まとめ

今回はいくつの典型的な例を紹介しました。どれも難しいことではなくシンプルなものですが、シンプルなものこそ気づきにくいかもしれないのですね。

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?