ふつーのプログラマです。主に企業内Webシステムの要件定義から保守まで何でもやってる、ふつーのプログラマです。

レインメーカー (16) テーブルとインデックス

»

◆アリマツ通信 2021.9.13
 
 DX 推進室が鋭意開発中の新CRM システムNARICS について、田代リーダーにお話を聞くことができました。田代リーダーによれば、現在、開発の7 割は終えていて、今月中にはアルファ版をリリースできる見込み、とのことです。「私を含めた開発メンバー9 人全員で力を合わせて開発を進めています。新人の5 名もすでに立派な戦力となっていて、大いに助けられています。新システムを作成するという桑畑さんの決断のおかげです」と語る田代リーダー。連日の残業による疲れも見せず、精力的に開発作業を指揮しています。
 私も何度か開発作業の様子を見学させてもらいましたが、システムを作成するということが、これほど大変なことだとは想像もしていませんでした。
 NARICS のデビューは、10 月に予定されているスポット業務になります。名古屋CC では今から期待する声も聞こえています。


 文 総務課 土井

 ◇ ◇ ◇ ◇ ◇

 使えない奴らだ。田代は内心の怒りを必死で抑え付けながら、居並ぶメンバーを見回した。こいつらは今日が何月何日で、どれだけの余裕が残っているのかを理解していないのか。
 毎週、月曜日に実施している定例ミーティングだった。メンバーの毎日の進捗はGit で確認しているので、ミーティングといっても実質的には先週の作業の振り返りにすぎなかった。実際、田代はミーティングに時間を取られるぐらいなら、実装を進めておきたかったのだが、桑畑副社長からの指示で仕方なく設定したのだ。桑畑はシステム開発部門の管理者など経験がなく、進捗が自分にもわかる形で記録されていないと不安で仕方がないらしい。会議とは時間を浪費し議事録を生み出すものだ、と言ったのは誰だったか。
 今日もメンバーが先週手がけた機能について順番に報告し、最後に田代がコメントして終わる予定だった。あとは記録係の土井が、適度に肉付けして膨らませた議事録を作成してくれる。そのはずだったのだが。
 その予定をぶち壊したのは、契約社員の倉田だった。倉田にはデータベース周りのロジックをアサインすることが多い。新人連中も何とかJava とSeasar2 については戦力になってきているが、SQL 文については倉田の経験に及ばないからだ。CC の中には数十万人の会員情報を扱うところもある。適切なインデックスも張っていない列をwhere 句に入れてSeq Scan を連発されてはたまらない。全てのSQL を田代がチェックすることなどできないので、倉田はDBA のような立ち位置になっていた。
 倉田は今日の定例ミーティングの冒頭、発言の順番を無視して挙手し、田代が指名するのも待たずに「テーブル構成、見直しませんか」と提案したのだった。
 全員が呆気にとられて倉田を注視した。新人の何人かが反応を確認するように田代に視線を向けたが、すぐに逸らされた。
 「あの」最初に沈黙を破ったのはイズミだった。「テーブル構成の見直しって、どのテーブルですか」
 「メインの2 つです」
 再び全員が息を呑んだ。倉田が口にしたのは、main_user_master と、main_history_data の2 つのテーブルだ。前者は氏名や住所、電話番号など電話をかけてきた人に関するデータ、後者は申込内容や問い合わせ、クレームなど受電したデータが格納される。重要度では双璧だ。ほとんど全てのロジックが、直接的、間接的にこの2 つを使うことになるため「メインの2 つ」と呼ばれている。もちろんすでに実装を終えたロジックも例外ではない。この2 テーブルを変更するということは、大半の実装をやり直すということになる。
 だがメンバーたちが絶句した理由はそれだけではない。この2 つを設計したのが田代だからだ。
 「見直す?」田代は何とか冷静な声を発した。「この時点でメインのテーブルを変更するというのは、かなりのリスクテイクになるのはわかりますよね。いったいメインの2 つにどんな問題があると言うんですか。私は特に問題を認識できないんですがね」
 「私は」を強調したのは、それとなく倉田を牽制する意図があったのだが、相手は顔色一つ変えなかった。
 「業務に応じてテーブルの列を増減させるのはスマートな設計だとは思いません」
 2 つのテーブルは倉田の言う通り、扱う業務が増えるたびに、業務独自の項目を追加していく前提になっている。たとえばmain_user_master は、userID を主キーとして「氏名」、「氏名カナ」、「住所」、「電話番号」、「性別」、「生年月日」など、どの業務でも使うような汎用項目を持っている。新業務で「喫煙の有無」という項目が必要になったとすると、列を一つ増やすことになる。<コールくん>のテーブルも名称は違うものの、同じ構造になっていた。ロジック内でalter table 文を発行して列を追加しているのだ。
 「システム設計はスマートかどうかで決めるものじゃないと思うんですがね」田代は笑った。「特に問題がなければ好みのレベルになって来ますよ」
 「問題はあります」
 「ほう。どんな?」
 「まずインデックスです」
 そう来ると思った。田代は内心でほくそ笑んだ。
 「なるほど、インデックスね」田代は頷くと、新人たちの方に顔をむけた。「君たち、倉田さんが何を問題だと思っているのかわかりますか? 俣野くん、どう?」
 突然指名された俣野(またの)カズマサはビクンと身体を伸ばした。専門学校卒で都内の実家から通勤している20 歳の男性だ。
 「え、あ、その......」俣野は助けを求めるように左右を見回した。「インデックス......すいません、わかりません」
 「池松さんは?」
 ある程度予測していたらしく、池松ノリコは動揺は見せなかったものの、やはり首を横に振った。
 「不勉強ですいません」
 「リーさん、どうかな」
 中国籍のリー・ウェイは生真面目そうな顔で田代を見返した。
 「検索用のインデックスが大量に作成されてしまう、ということでしょうか」
 「おお、いいね。倉田さんの懸念点もそれってことでいいですか?」
 倉田は黙って頷いた。A 業務では氏名カナの検索、B 業務では電話番号での検索、C 業務では性別と生年月日での検索が業務要件として必要ということであれば、3 つのインデックスが必要となる。実際には一つの業務で複数の検索項目が必要になるのが通例なので、インデックスの数はさらに増えていくことになる。
 「それで倉田さんの懸念点は何ですか」田代は退屈そうな口調で訊いた。「インデックスがたくさんあると登録や更新が遅くなるとでも?」
 「それもありますが管理コストの増大も心配です。たとえば業務が終了になったとき」
 「業務終了で、その業務で使っていたインデックスが不要になったとき、ってことですか。相沢くん、インデックスが不要になったらどうする?」
 「えー」いつも笑っているような顔の相沢は、おどけた声で答えた。「ズバッと消しちゃうってのはありですか」
 「ズバッとね」田代は笑いながら次の新人を指した。「綱川くんはどうかな」
 大学を一年留年したという綱川はすぐに答えた。
 「すぐに消してしまうのはマズい気がします」
 「どうマズい?」
 「いろいろ影響が出てきそうな、その、パフォーマンスとか何かで......」
 「何も考えずに削除して」苛立ったように倉田がかぶせた。「そのインデックスを他の業務で使っていたらどうするのか、ってことです。他の全部の業務を調べて、該当のインデックスを誰も使ってないと確信が持てないと削除はできないでしょう。業務が追加されたときも同じです。安易にインデックスを追加するんではなく、他の業務で同じインデックスがすでに定義されていないかを調べる必要があるじゃないですか」
 「私の経験から言うと」田代は言った。「テーブル定義書をしっかりメンテナンスしていれば、そういう事態は発生しないと思いますね。どの業務でどのインデックスを使っているかを記録しておけばいいだけの話です」
 「私の経験から言うと」倉田は反論した。「ドキュメントのメンテナンスはコストが高いので、システムのカットオーバー時には意欲的にソースと同期が取れていても、時間が経ったり、担当者が変わったりすると、その頻度が落ちてくるものです」
 沸き起こった怒りの噴出を、田代は何とか押し戻した。
 「あのね、倉田さん」かなり苦労して声を抑えた。「ひとつお忘れじゃないですかね。searchOnlyKey 列が作ってあるでしょう。業務キーとsearchOnlyKey を使えば、むやみやたらにインデックスが増えることはない。違いますかね」
 searchOnlyKey はテーブル設計時に追加した列で、pg_bigm のインデックスが設定してある。pg_bigm は日本語に対応した全文検索用インデックスだ。業務毎に検索項目が異なることを考慮した列である。ここに格納される値は業務毎に異なる。10 月に行われるQSS 案件では、会員番号を忘れたユーザのために、電話番号と生年月日での会員検索が必要になるので、「|09055550000|20011231|」のような値をセットしておく。電話番号での検索をかけるときは、like '%|09055550000|%' で行えばいい。
 「その方法にも問題があると思いますよ」倉田は首を横に振って指摘した。「まず、検索項目が増えた場合、過去に登録した全データを更新する必要があります」
 「やればいいじゃないですか」自分の声が尖っているのを意識したが、田代は構わずに言った。「何の問題があります?」
 「数十万件の更新の場合、かなり時間がかかることになりませんか。となると業務時間内では無理なので、夜間バッチか何かでやることになります。以前、聞いたところでは、将来的な構想としてエンドユーザが管理画面からある程度のメンテナンスを行えるようにする、ということでしたね。その方針に反しませんか?」
 「そんな将来の話をされてもね」
 「まだあります。キーを登録するロジックにバグがあってもエラーが出るわけじゃないので、長い間、不具合が発覚しない可能性もあります」
 「仮定の話ですね、それは」
 「仮定を想定して、あらかじめ潰せるものは潰しておくのが、システムの設計じゃないんですか」
 田代は苛立った。その苛立ちを増幅させたのは、倉田の言葉そのものよりも、山下が同意するようにウンウンと頷いているのを目にしたことだった。田代が睨むと、山下は肩をすくめたが、その仕草が自分をバカにしているようで、苛立ちは収まるどころか複利計算で増えていった。
 「いい加減にしてくれよ」ついに敬語を使う余裕すらなくして、田代は低い声で言った。「前に言っただろう。この開発は独裁で行くって。テーブルは俺が決めたんだから、それに従って実装を進めてもらう。もうこの議論は終わりだ」
 これで口を閉ざすだろう、と思ったが、案に相違して倉田は言葉を発するのをやめなかった。ただし、今度の相手は田代ではなかった。
 「朝比奈さんはどう思いますか」
 黙って聞いていたイズミは、驚いたように身体を浮かせかけた。知らない人間が見たら、居眠りでもしていたのか、と疑うところだ。
 「私ですか」
 「はい。サブリーダーとして意見を聞かせてもらいたいんです」
 逡巡したイズミが、許可を求めるように田代を見たので、田代の溜飲はかなり下がった。小さく頷いてやる。
 「ちょっと判断ができませんが......」イズミはテーブルの上で両手を組み合わせながら答えた。「ちなみに、倉田さんはどのように改良しようと仰ってるんですか」
 すると倉田はクリアファイルからプリントアウトの束を取り出すと、先頭の一枚をイズミの方に滑らせた。残りを山下に渡して、全員に回すように頼む。

tableLayout.png
 「単純化したものですが、こんな感じです。main_user_master に業務で必要な項目を追加していくのではなく、fieldMaster に行として追加していきます。実際の値が入るのはmain_user_field テーブルになるわけです」
 イズミはしばらくプリントアウトを見つめていたが、すぐに顔に理解の色を浮かべた。
 「ああ、なるほど。value 列にインデックスを貼るってことでね」
 「そうです。これならインデックスが一つで済みます」
 「こういうパターンは見たことがあります」山下も声を上げた。「value のところが文字型、日付型、数値型、ブーリアン型みたいにいくつかありましたけどね。ああ、大丈夫です。これは単純化した図ってことですね。わかってます」
 「なるほどです......」
 イズミが呟きながらプリントアウトに書き込みをしているのを見て田代は焦燥感に駆られた。
 「ちょっと待てよ......」田代は考えがまとまらないまま声を上げた。「いや、待ってください。これはこれでまた問題があるんじゃないですか」
 「もちろん検討の余地はたくさんあると思っています」倉田は落ち着いていた。「たとえばどんなところか訊いていいですか」
 「えー、そうですね」田代は必死で頭を回転させた。「すぐに思いつくのは......」
 「main_user_field のレコード数が多くなるってことですね」言ったのはイズミだった。「main_user_master のレコード数かけるfieldMaster のレコード数になるわけですから。現行レイアウトだとmain_user_master のレコード数です」
 イズミが自分の思考をそのまま素直に出力しているだけなのは理解していた。それでも田代は助け船を出された気になった。新人たちの視線の質が変わってきている気もする。これはまずい。リーダーが技術力を疑われては、今後の開発に差し障りが出る。
 「私もそう言おうとしていたところです」田代は議論の主導権を握っているのは、あくまでも自分だと示すように声を上げた。「それに現行案なら、main_user_master だけで必要な全項目が取得できますが、こうテーブルを分けるとJOIN しなければならないから、パフォーマンスが落ちますね、確実に」
 倉田が反論してくる、と田代は身構えたが、拍子抜けすることに何も言ってこなかった。
 「確かに」イズミが頷いた。「それも考えられますね」
 「私は倉田案の方がいいと思うんですけどねえ」
 そう呟いた山下の言葉が、田代の心を決めた。
 「確かに倉田さんの案にも利点はあります」田代は全員を見回した。「将来的には取り入れることを検討してみてもいいでしょうね。ただし、今回はQSS 案件に間に合わせるという絶対条件があります。今から倉田案に沿って改修を行った場合、スケジュールが大幅に戻ることになります。残念ですが、それは上の人たちが認めてはくれないでしょうね。パフォーマンスの問題もあるので、このまま進めることにします。これは決定事項です」
 会議室は静まりかえった。土井がキーを叩く音だけがかすかに聞こえている。田代は倉田を見やったが、相手はこうなることは想定の範囲内、とでも言うように腕を組んで目を閉じていた。
 これでいいんだ。田代は自分に言い聞かせた。スケジュールの点では間違っていない。だいたい倉田も倉田だ。こんな大きな提案を、ここまで設計と実装が進んだ今になって言い出すとは。もしQSS 案件にNARICS が完成しなかったら、もしくは完成したとしても不具合だらけで使い物にならなくなったら、どういうことになるのかわかっているのか。DX 推進ユニットそのものが存在意義を問われることになりかねないんだ。今はとにかく、NARICS の完成そのものを最優先させるべきだ、ということが理解できていないようだ。
 「さてと」田代はプリントアウトを無造作に放り出すと、新人たちの方に笑顔を向けた。「少々、脱線したが、なかなかいい勉強になったんじゃないか? ではいつも通り、先週の報告をしてもらおうか。俣野くんから」
 いつもよりも緊張した声の報告を聞きながら、田代は安堵感に浸っていた。そのため、イズミと倉田が意味ありげな視線を交わしたことに気付かなかった。

(続)

 この物語はフィクションです。実在する団体名、個人とは一切関係ありません。また、特定の技術や製品の優位性などを主張するものではありません。

 ◇ ◇ ◇ ◇ ◇

 次週の月曜日は私用のためお休みします。
 週末にクリスマス読み切り短編を予定しています。

Comment(16)

コメント

匿名

これもイズミの仕込みかな

匿名

勉強不足で申し訳ないですけど、これってアンチパターンな設計じゃ・・・?

h1r0

罪と罰でもやってたやーつ

yupika

わざと論破される仕掛けにしていた…いったいなぜ!?
(揺さぶってイズミに精神状態を読ませるため?)
その衝撃の真実は来年かあ…。
今年もお疲れさまでした。

匿名

イニシアティブの回し者かな?

DBA

匿名さん
>勉強不足で申し訳ないですけど、これってアンチパターンな設計じゃ・・・?

田代案、倉田案のどっちが?
ちなみに自分なら倉田案採用ですな

ちゃとらん

昔、部品表システムで、属性を動的に追加できる外部パッケージを導入したことがありますが、一般的なテーブル設計の100倍以上遅かった記憶があります。(100倍以上というのは実測値です)


ユーザーによる動的なカラム追加が『必須仕様』なら仕方ありませんが、そうでなければメリットは少ないと思います。


# 実際、速度の問題より、処理が複雑になりメンテナンスが大変になる事の方が、システム屋にとっては嫌ですけど。

侘助

田代さんはハナからいけにえ役として採用されたのかな。
いろんな人から大事にされてない感と信用されていない感が・・

システム完成の暁には、本人の関与いかんにかかわらず不都合なことをおっかぶされて追い出される。

勉強不足エンジニア

すいません、言葉足らずで混乱させてしまいました。
名前もつけさせていただきました。
>DBAさん
倉田案がEAVに当たるのかなと想定してました。
1つのカラム(ここでいうとValue)に複数の意味合いを持つのってどうなのかなって考えてました。

DBA

自分はValueに複数の意味を持つのはそんなに気にならないです
全部Stringにしてぶちこむというのは抵抗あるので
やるなら山下が言ってるように文字型、日付型、数値型ぐらいのカラムは用意しますけどね
EAVにあたるのかどうかは微妙ですね
倉田案だとfieldMasterというのがあって、図ではfieldidだけになってますが、実際はここに属性名とかいろいろ入ってくると推測(つまりfieldmasterで項目の管理ができる)

シサム

以前、外部参照されてる列に張ったインデックスを削除したらえらい目に遭ったことがあります。
その列を更新する際に行が確定できないので、行ロックではなく表ロックがかかってしまう(参照元にも先にも)。

非正規化を突っ走る動的な列追加は、私なら設計時に止めさせます。
あと、valueに複数の型を持たせるならraw型でしょうか。
性能と容量は分かりませんが。
とにかく田代さん無能にされ過ぎてる感じはしました。

シサム

追記です。
田代案でいくならmain_user_masterはビューにした方がよいかと思いました。
実体表は倉田案で。

匿名

O/Rマッパー使うなら、倉田案しかないのでは?
テーブルに対応したモデルクラス使うだろうから列が動的に増減したら、いちいちソース直すことになる

匿名D

ちょっと揺さぶりをかけられたら、
差し出された餌に即座に、そして言い訳をしながら食らいつく。
ちょろい、ちょろすぎるぞ、田代氏。
本人は、ちゃんと地歩を確保しているつもりなのか?
次は、つんのめったとこを首根っこを掴まれて引き戻されるんだろうか。


それにしても、現在のイズミ女史は
さしずめマックスウェルの悪魔といったところか。
どんどんどんどんエントロピーを自身に蓄積しているようだが。
まったく入社したばかりの社員の(ry
躓いて抱えているものをぶちまけることになったら、
その反動は田代氏の比じゃないぞ。
まあ、躓くんだろうが。

匿名

テーブルの設計に関して言うとどっちもどっちに見えますね。
田代案のsearchOnlyKeyの検索なんてそれこそ全行探索しないと候補が出せないし。

テーブルを増やさず列を増やすことのメリットって何があるんでしょうか。
ロジック的な非効率がテーブルの結合のコストより大きいように見えます。

DBA

>田代案のsearchOnlyKeyの検索なんてそれこそ全行探索しないと候補が出せないし。

全文検索のインデックス張ってあると言ってるから、全行探索にはならないですね

コメントを投稿する