risou's Lithograph

ISUCON 10 も予選で惨敗しました

2020-09-19

予選開催から1週間が経過し、公式による解説も公開されたので自分の体験を記録しておく。

ISUCON10 予選問題の解説と講評 : ISUCON公式Blog

自チームのスコアも公式 Blog の全チームスコアからスクショ。

メンバー

前回 と同じ。
同じメンバーで継続して参加できているのは素直に嬉しい。

環境

今回は3人で集まる先の当てもなく(正確には当てはあるが、世間の情勢からみて推奨されない)、全員が自宅の作業環境を利用する形でオンラインで参加した。

当日やったこと

開始まで

30分前には集合できるように朝から用事をこなして挑んだが、開始時間が10時から12時に変更になった。
各々やるべきことはたくさんあるので、11時30分を目処に再集合することに。

事前に VC にどの環境を使うかだったり、リポジトリを用意しておいたりしてあったので、そのあたりを予定通りにそろえて後は開始を待つだけ。

開始直後

開始直後はポータルサイトが重く、ベンチマークを回すことができなかったりしたこともあり、 ISUCON の Discord サーバで運営から伝達された情報を元にマニュアルを見つけて読んだり、提供されたインスタンスへの接続を確認したりした。

僕がマニュアルに目を通している間に、チームメンバーの2人はインフラ周りの初期設定やローカルでアプリケーションを動かすための準備を整えてくれていた。
今回は New Relic を無料で使えるということもあり、そのあたりのセッティングも最初にしてもらった。

自分が最初に手を動かしたのは Logger の変更だったはず。

どこから手を付けるか

自分が見るべきはアプリケーションロジックかな、と目をつけソースコードを一通り読み込む。
読んだ感想として、まずはインデキシングをちゃんとやるべきだな、と考えたり、「椅子に合う物件」の判定ロジックが物件の扉の大きさと椅子の大きさを比較して椅子が扉を通れるか判定しているのがシュールだな、という感想を抱いたりした。

この「椅子に合う物件」を検索するクエリは冗長だな、と思ったのでウォーミングアップを兼ねて軽く直してみた。
このときに作った PR は途中でマージしたけど、あまりスコアには貢献しなかったように思う(害はなかったのでそのままになった記憶)。

インデックスを作成

まずはわかりやすく ORDER BY hoge ASC, fuga ASC になっているところに対応するインデックスを作成。

次に ORDER BY hoge DESC, fuga ASC になっているところをなんとかしたいなー、と考えたものの MySQL 5.7 では ASC と DESC が混在するソートにインデックスを聞かせることができないため、これはなにか工夫が必要だ、となって放置。
解説を見てもらうとわかるが、ここは対応すべき場所であり、放置してしまったのは当然敗因の一つ。
DESC でソートしているカラムの値を全てマイナスにして ASC にするの、全然難しくないし気づきたかったけど、やってたとき気づけなかったので絶望ですね。

ちなみに普段 MySQL を触ってなさすぎて INDEX 作成の構文をミスって反映されなかったりエラーになったりして時間を浪費してしまったので、ここも反省点です(ごめんなさい)。

迷走

インデックス作成後もそんなにスコアが伸びなかったこともあり、焦って思いつくことを乱雑に試してしまった。

SELECT * のところカラム指定してみると良くなるかな、と思って試したり、定番戦術としてセッション有効にしてみたけどそもそもログインとかの概念がなかったりして、ここでも時間を浪費してしまった。

N+1 の解消に挑む

そうこうしているうちに、優秀なチームメンバーがなぞって検索が N+1 になっていることに気づいてくれたので、ざっと実装を見て N+1 を根本的に解消する方法と、 N+1 は解消できないけどクエリ発行回数を抑えられる方法を検討した。
チームメンバーに後者を担当してもらい、自分は N+1 の解消に挑んだが、最終的にできた PR をマージして試したところスコアが若干下がったため、 N+1 の解消は諦める形でリバートした。
ちなみにチームメンバーが作ってくれたクエリ発行回数を抑える PR は先んじてマージされ、こちらは効果があった。

CSV インポート処理の改善

用意されている2つのテーブルに対し、それぞれ CSV インポート機能が実装されていて、これがどちらも重そうだったので対応することに。
トランザクションを使って CSV をパースして1件ずつ INSERT をかけていたので、全県まとめて BULK INSERT するように変更してもらった。
この変更も効果があり、スコアを少し押し上げてくれたと記憶している。

お片付け

時間が迫っていたので New Relic 外してベンチマーク流し直して、 fail は避けられそう、かつチームとしては最高スコアが出そう、というのがわかったところで終了した。

感想

今回はデータベース周りの改善ポイントが非常に多く、全員が普段 MySQL を触っていないという現実が非常に重くのしかかった結果だったと思う。
Discord での感想戦の会話を追っていく中で、 MySQL のバージョンを 8 に上げたチームの話を聞いたりしてその手があったかと膝を打ったり、2テーブルしかなくて結合したクエリないからテーブルごとにインスタンス分けた、という話には「なるほどその手が……!」という驚きと自分たちがその手に気づかなかったことに対する絶望を味わわされたりした。

最初にリンクを張った解説を見ていても、注目すべきポイントはそんなに外していなかったな、という感じがしており、「もっと早く気付けていれば」「気づいた問題にちゃんと対処するだけの技術力があれば」という思いを抱かざるを得ない結果だった。
つまり実力不足……。

もっと腕を磨いて出直してこい、ということですねわかります。
そういえば以前どこかで「ISUCON 今回で一区切り説」を耳にした気がするのだけど、終了後のアンケートなどに「次に向けて意見等あれば」みたいな項目があって次回開催が期待できるな、と認識を改めたので、次回に向けてちゃんと腕を磨こうと思います。

2020-09-19T16:54:58.719720+09:00