Example を見ただけて直感的にどういうことをしてくれるフレームワークか伝わる、やりたいことのほとんどがフレームワークによって考慮済みである、といった条件が整えば、そのフレームワークはどんどん使われていくことになるだろうし、フレームワーク自体にガタが来ることも少ない(大量の変化を必要としない、健全に進化する)はずです。
SELECT
c.table_name,
c.column_name,
c.data_type,
e.data_type AS element_type,
c.is_nullable,
c.character_maximum_length
FROM
information_schema.columns c
LEFTJOIN information_schema.element_types e
ON ((c.table_catalog, c.table_schema, c.table_name, 'TABLE', c.dtd_identifier)
= (e.object_catalog, e.object_schema, e.object_name, e.object_type, e.collection_type_identifier))
WHERE
c.table_name = 'users'ORDERBY
c.table_name, c.ordinal_position
data_type には character varying のような文字列が入っている。
PostgreSQL には array 型があるが、その場合は data_type に array が入っていて、element_type に character varying が入っている。
また、character varying のような型には character_maximum_length が入っている。( text 型の場合は 0 になる)
ただし、この方法だと型は文字列として取得されるので、文字列比較で処理を書く必要があり、若干不安な気持ちになる。(まぁこの文字列表現に非互換な変更をいれてくることは想像し難いので気持ちの問題だけど) PostgreSQL には oid というのがあって、そっちを使うほうが安心かもしれない。同じようなクエリで oid も取得できる。
Count: 1283 Time=0.02s (19s) Lock=0.00s (0s) Rows=10.1 (12972), isucon[isucon]@2hosts
SELECT * FROM reservation_slots WHERE start_at >= N AND end_at <= N FOR UPDATE
Count: 74228 Time=0.00s (8s) Lock=0.00s (0s) Rows=0.0 (0), isucon[isucon]@2hosts
COMMIT
Count: 1162 Time=0.01s (6s) Lock=0.00s (0s) Rows=0.0 (0), isucon[isucon]@2hosts
INSERT INTO icons (user_id, image, sha256) VALUES (N, _binary'S', 'S')
Count: 31976 Time=0.00s (4s) Lock=0.00s (0s) Rows=1.0 (31976), isucon[isucon]@2hosts
SELECT * FROM livestreams WHERE id IN (N)
Count: 3514 Time=0.00s (3s) Lock=0.00s (0s) Rows=50.0 (175700), isucon[isucon]@2hosts
SELECT user_id, sha256 FROM icons WHERE user_id IN (N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N)
Count: 96 Time=0.04s (3s) Lock=0.00s (0s) Rows=1.0 (96), isucon[isucon]@2hosts
SELECT rank_
FROM (
SELECT id, RANK() OVER (ORDER BY score DESC) AS rank_
FROM livestreams
) AS ranked_users
WHERE id = N
Count: 3514 Time=0.00s (3s) Lock=0.00s (0s) Rows=50.0 (175700), isucon[isucon]@2hosts
SELECT * FROM themes WHERE user_id IN (N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N)
Count: 11287 Time=0.00s (2s) Lock=0.00s (0s) Rows=0.0 (0), isucon[isucon]@2hosts
INSERT INTO livecomments (user_id, livestream_id, comment, tip, created_at) VALUES (N, N, 'S', N, N)
Count: 9851 Time=0.00s (2s) Lock=0.00s (0s) Rows=16.1 (158932), isucon[isucon]@2hosts
SELECT * FROM livecomments WHERE livestream_id = N ORDER BY created_at DESC
Count: 9883 Time=0.00s (2s) Lock=0.00s (0s) Rows=15.1 (149160), isucon[isucon]@2hosts
SELECT * FROM reactions WHERE livestream_id = N ORDER BY created_at DESC
...
最終盤にきても CPU が 7 割くらいしか使い切れず、なにがボトルネックなのかいまいち分からなかったので、「スコアは上がらないけど速くなっている/負荷が下がっている」みたいな変更を最終盤にガンガン取り込んだのですが、そのなかの一つが fail の原因でした...