クラウドワークス エンジニアブログ

日本最大級のクラウドソーシング「クラウドワークス」の開発の裏側をお届けするエンジニアブログ

パフォーマンス改善:効率的なCSVインポートでSQL発行回数を大幅削減

はじめに

はじめまして、クラウドログのバックエンド開発を担当している崎岡と申します。

クラウドログは、プロジェクト管理や工数管理を効率化するためのSaaS、作業時間の入力や進捗の可視化を簡単に行える機能が特徴です。そのプロダクトの機能改善について今回はお話ししようと思います。

今回お話しすること

クラウドログには重要な要素「工程」と呼ばれる業務の種類を表すマスタが存在します。
しかし、この機能はかなり昔に Perl で実装されており(今のクラウドログのメイン言語は Golang)、システム負荷の改善があまり行われていませんでした。今回はこの機能のパフォーマンス改善をした経緯とその成果についてご紹介します。

なぜやろうと思ったのか?

改善の動機は主に以下の4点です。

• 他のメンバーが中々対応できない Perl で実装されていた。
• 性能改善の経験があり、個人的にチャレンジしてみたいタスクであった。
• ユーザーにとって重要な機能であり、優先的に対応が必要なものだった。
• 改善によって今後の保守コストを削減でき、更なるプロダクト開発に集中できる。

どんな負荷があったのか?

大量のデータ更新を行う際、工程を管理する画面では、更新の完了までに非常に長い時間がかかり、その結果、データベースにも大きな負荷がかかってしまう問題が発生していました。

負荷の主な原因

これは、発行されるSQLが遅いクエリだったわけではありません。問題は、更新処理を実行しているプログラムが以下のように大量のSQLを発行していたことにあります。

上記は計算量オーダーで言うところの O(N2) となります。図のような for 文の二重ループなどで発生します。サービスの規模が小さいうちは問題になりにくいですが、サービスが成長し、データ量が増えてくるとループの回数も増え、大量のSQLを発行する問題が顕在化しやすい処理かと思います。

どう改善したのか?

二重ループでネストしていることが原因ですので、ネストせずに一回のループで最新の工程データなるロジックに変更、SQLの回数を抑える形にします。これで一度に大量のSQLを発行し、データベースに高い負荷がかかるのを解消できます。

【改善後のロジック】
1. 更新対象のプロジェクトをループ処理する
2. ループの中で一括 DELETE
3. 最新の工程を一括 INSERT

ループをネストさせずに古い工程の DELETE と最新の工程での INSERT を行う形になります。計算量オーダーは O(N*2) となります。

図にすると以下のようになります。

以下、実際のデータでループ中の SQL 発行回数を比較したグラフとなります。

グラフは左が改善、右が改善になります。

SQLの回数
改善前 991530
改善後 9580

ご覧通り SQL の回数を100分の1まで減らし、大きく改善できました。

データの依存関係を見て二重ループのプログラムを書き、その中で SQL を発行するといのは初心者のうちは書いてしまいがちかと思いますので、注意をしながらコードを書いたり、あるいはレビューなどで防ぐことはできるかと思います。

改善を終えて・感想

今回の改善により、CSVインポート機能の負荷を大幅に軽減することができ、非常に達成感を感じています。エンジニアとして、性能改善に取り組むことは私にとって非常にやりがいのある仕事です。コードを修正し、実際にパフォーマンスが向上する瞬間は、いつも喜びを感じます。前職でも同様の作業を好んで行っていたことから、私はこのような仕事が本当に好きなんだと思います。

そんな私の所属する開発チームでは、挑戦を楽しみ、かつユーザーの課題を解決できるプロダクトを作りたい!!と感じるエンジニアを求めています。もしプロダクトを改善することに興味があるなら、ぜひ私たちと一緒に働きませんか?。詳しくは採用情報をご覧ください。

© 2016 CrowdWorks, Inc., All rights reserved.