基本的に怠Diary

主に日常と作ったものを書いていく。

k3s + Drone CI/CD構築体験記① なんもわからんまま失敗

mintblog.hatenablog.com

前々回くらいproxmoxでk3sをデプロイした。

せっかくなのでさらなる遊びに興じようと思いついたのがローカルブログの自動デプロイだ。

雑に両方ともPodとして配置して、CI/CDPodからHugoのPodを更新するような構成にチャレンジしてみた。

結論だけ言えば、失敗した。

結論までの過程については生成AIとのやりとりを生成AIにまとめてもらって記事にした。

目標設定

  • GitHub → Drone CI/CD → Hugo静的サイト生成 → k3s自動デプロイ
  • 最終的にはGiteaによる完全自己完結環境を目指す

事前知識レベル

  • k3s: かなり前に少し遊んだ気がする
  • Drone: 全くの未経験
  • CI/CD: GitHub Actionsを簡単に動かす程度

k3s基本コマンド習得表

カテゴリ コマンド 用途 学習ポイント
リソース確認 kubectl get pods -o wide Pod状態とノード配置 -o wideで詳細情報取得
kubectl get svc --all-namespaces 全サービス確認 名前空間跨ぎでの確認方法
kubectl get all -n namespace 名前空間内全リソース リソース種別を一括確認
デバッグ kubectl logs deployment/name --tail=20 デプロイメントログ --tailでログ量制限
kubectl describe pod pod-name Pod詳細・イベント確認 エラー原因特定の必須コマンド
kubectl get events --sort-by='.lastTimestamp' 時系列イベント確認 トラブルシューティングの基本
運用操作 kubectl set image deployment/name container=image:tag イメージ更新 ローリングアップデート実行
kubectl rollout status deployment/name デプロイ状況確認 更新完了待ち
kubectl create namespace name 名前空間作成 リソース分離の基本
調査・実験 kubectl exec deployment/name -- command Pod内コマンド実行 内部状態確認・デバッグ
kubectl port-forward svc/service 8080:80 ローカルアクセス 動作確認・テスト

Drone CI/CD構築過程

最初の誤解: Serverのみで動作すると思った

問題: drone-serverをデプロイして数時間、ビルドが"Step is pending"のまま動かない

原因: Droneアーキテクチャの理解不足 - drone-server: Web UI、API、ジョブ管理 - drone-runner: 実際のビルド実行エンジン

学び: 分散アーキテクチャでは各コンポーネントの役割を明確に把握する

Docker前提の罠: containerdとの競合

問題: drone-runner-dockerが"Docker daemon not found"エラー

原因: k3sはcontainerdランタイム、Dockerソケット存在せず

解決: drone-runner-kubeに変更 - k8sネイティブな実行環境 - Podとして各ステップを実行

GitHub OAuth設定の学習

必要な権限スコープ: - write:packages (GHCR push用) - read:packages (GHCR pull用) - repo (プライベートリポジトリ用)

Token種別: Classic推奨(Fine-grainedは一部CI/CDツール未対応)

成果と課題

成功した部分

  1. GitHub OAuth認証完全動作
  2. Drone Server + Runner連携成功
  3. Hugo自動ビルド実現
  4. GitHub Container Registry連携
  5. 手動k8sデプロイ動作確認

未解決課題

  1. k8s自動デプロイ: 権限設定・ServiceAccount構成
  2. ファイル消失問題: Docker buildでは存在するが、k8s Pod内で消失する謎
  3. 監視・ロールバック: 失敗時の自動対応

技術的教訓

1. アーキテクチャ理解の重要性

生成AIに頼りすぎず、公式ドキュメントで全体像を把握すべきだった

2. 段階的検証の必要性

一気に全体を構築せず、各コンポーネントを個別に動作確認すべき

3. ログ・デバッグ文化

kubectl logskubectl describeを習慣化することでトラブル解決速度が向上

次のステップ: Gitea移行計画

目標

GitHub依存からの脱却、完全自己完結CI/CD環境

構成予定

  • Gitea: Git リポジトリサーバー
  • Drone: CI/CDエンジン(継続使用)
  • Harbor: プライベートコンテナレジストリ
  • k3s: デプロイ先環境

期待される利点

  • 外部サービス依存の排除
  • プライベートリポジトリ無制限
  • 完全なアクセス制御

まとめ

理想的なCI/CDパイプラインの90%は実現できたが、最後の自動デプロイで挫折。しかし、k3s運用スキル、Droneアーキテクチャ理解、GitHub連携など多くの知識を獲得。次はGitea移行で完全自己完結環境を目指す。

BTreeを実装しながら学んだ設計の破綻と修正

リポジトリ: GitHub - wasuken/btree_pj

最初のアプローチ(bulk loading)

配列を渡すと勝手に構築してほしいのでコンストラクタをそのように作った。 _split_recursively関数で実施する。 ここは簡易的に実装した。二分割ずつみたいなことしたから、そんな早くはならないかも。 検索は楽々できた。 これまでは再帰処理を採用することが多かったが、今回は素直にループで処理した。

Insert実装での設計破綻

BTreeの構成上順番に自分よりでかい場所まで移動して、さらにそこの間のNodeで 同じような検索をしていく実装にした。 NodeKeysが10,20,30とすると、子Nodeはそれぞれ-10,10-20,20-30,30-と存在するようになる。 keysをLoopすると3つまではできるが、一つ足りない。 Btreeはソートされているので効率よく比較演算子で範囲を指定できる。 なので、今回前から一つずつ見て小さければそこから子要素へカレントNodeを移動、 最後のインデックスになったときには強引に以上の場合というものを見るようにした。

only_data_copyによる解決

対象のノードについてはポインタを変えずに中身だけ移し替える。 Insert時にはこれでギリギリ次第点な動きになってる・・・気がする。

Delete実装での親参照問題

only_data_copyでほぼゴミになっていたが、Deleteでうまいこと調整がかけなかったので 諦めて再調整するようにした。おそらく削除処理は世界で一番遅いBTreeが爆誕した。

計測一回目->Setに惨敗

=== BTree (Search Heavy) ===
Insert 50 values: 0.000 seconds
10000 searches: 0.032 seconds
Delete 25 values: 1.981 seconds

=== SimpleList (Search Heavy) ===
Insert 50 values: 0.157 seconds
10000 searches: 8.328 seconds
Delete 25 values: 0.045 seconds

=== SetWrapper (Search Heavy) ===
Insert 50 values: 0.000 seconds
10000 searches: 0.005 seconds
Delete 25 values: 0.000 seconds

比較は生成AIに作ってもらったSimpleListとSetWarpper(Set)と比較する。 当然だが、Deleteでは惨敗。 そしてこれも当然だが、単体検索でもSetに惨敗。 そりゃそうだ。

計測二回目->範囲検索で俺Tueeeeeeeeeeeeeeeeee

=== BTree (Search Heavy) ===
Insert 50 values: 0.000 seconds
10000 searches: 0.038 seconds
100 range searches: 0.007 seconds
Delete 25 values: 2.395 seconds

=== SimpleList (Search Heavy) ===
Insert 50 values: 0.174 seconds
10000 searches: 9.320 seconds
100 range searches: 0.544 seconds
Delete 25 values: 0.062 seconds

=== SetWrapper (Search Heavy) ===
Insert 50 values: 0.000 seconds
10000 searches: 0.006 seconds
100 range searches: 0.703 seconds
Delete 25 values: 0.000 seconds

というわけで範囲検索を実装・・・しようとしたがバグだらけでもうだめだとなったので 諦めて生成。 結果、範囲検索についてはしっかりと勝利。俺Tueeeeeeeeeeeeeeeeee!!!!

感想

LeetCodeをやっているとはいえ、実装力はしっかりとゴミ。 てかこういうときこそ再帰処理頑張りたかったけど、うまいことやれなかった。 多分しっかりした実装は全部生成AIに任せたとこだけ。悲しい。

ProxmoxでK3sクラスターを構築する:LXC環境での完全ガイド

概要

ProxmoxのLXCコンテナ上でK3sクラスターを構築した際の実体験をまとめる。

構築は生成AIに確認しつつ、エラーログをコピペしながら進めていった。

生成AIの言うとおりにすればすべてそのままうまくいく・・・こともなかったので

自宅ラボ環境においてk3s環境を構築するまでの手順と、実際に遭遇したトラブルの解決方法を記事にしていく。

環境・前提条件

ハードウェア環境

  • Proxmox VE 9.x系
  • 利用可能RAM: 16GB
  • ストレージ: 50GB以上の空き容量

ネットワーク環境

  • 外部ネットワーク: 192.168.100.0/24
  • 内部ネットワーク(作成予定): 10.0.0.0/24
  • 既存サービス: Nginx Proxy Manager等

前提知識

  • 基本的なLinux操作
  • コンテナ技術の概要理解
  • Proxmoxの基本操作

クラスター設計

ノード構成

ノード名 役割 CPU RAM ストレージ IP
k3s-master Control Plane 2コア 2GB 10GB 10.0.0.10
k3s-node01 Worker 2コア 1.5GB 8GB 10.0.0.11
k3s-node02 Worker 1コア 1GB 8GB 10.0.0.12

合計リソース

  • CPU: 5コア
  • RAM: 4.5GB
  • ストレージ: 26GB

構築手順

1. Proxmoxホスト側の準備

カーネルモジュールの有効化(重要):

# Proxmoxホストで実行
modprobe br_netfilter
modprobe overlay

# 永続化設定
echo 'br_netfilter' >> /etc/modules
echo 'overlay' >> /etc/modules

# 確認
lsmod | grep br_netfilter
lsmod | grep overlay

注意点:この手順を行わないと、後でk3sサービスが起動失敗を繰り返した。

2. LXCコンテナの作成

手動作成の場合:

  1. ProxmoxのWeb UI > Create CT
  2. Template: ubuntu-22.04-standard
  3. Disk: 上記表の通り設定
  4. CPU/Memory: 上記表の通り設定
  5. Network: vmbr1(内部ネットワーク用)

例外ケース:

  • ネットワークブリッジが存在しない場合は事前に作成が必要
  • 十分なリソースがない場合、最低限Master 1.5GB、Worker 1GBでも動作

3. 各LXCコンテナの初期設定

全ノード共通

# パッケージ更新
apt update && apt upgrade -y

# 最低限ツールインストール
apt install -y curl

# k3s用設定ファイル作成
# curlによるk3sのinstall前に実施した場合、失敗したこともあったので
# 後に行って、k3s,k3s-agentの再起動をすると動作した事象があった。
mkdir -p /etc/rancher/k3s
tee /etc/rancher/k3s/config.yaml << EOF
kubelet-arg:
  - "feature-gates=KubeletInUserNamespace=true"
  - "cgroup-driver=cgroupfs"
disable:
  - metrics-server
EOF

重要な注意点:LXC環境ではKubeletInUserNamespace=trueが必須です。これを設定しないと以下のエラーで起動失敗する:

Error: failed to run Kubelet: failed to create kubelet: open /dev/kmsg: no such file or directory

4. Masterノードの構築

k3sインストール

# LXC対応オプション付きインストール
curl -sfL https://get.k3s.io | sh -

起動確認

systemctl status k3s
kubectl get nodes

トラブルシューティング

サービスがactivating状態で止まる場合:

# 詳細ログ確認
journalctl -u k3s -f

# カーネルモジュール問題の場合は前述の手順を実行
# その後再起動
systemctl restart k3s

成功時の出力例

NAME         STATUS   ROLES                  AGE   VERSION
k3s-master   Ready    control-plane,master   1m    v1.33.6+k3s1

5. Workerノードの追加

トークン取得

# Masterノードで実行
sudo cat /var/lib/rancher/k3s/server/node-token

Workerノードでのjoin

# 取得したトークンとMasterのIPを指定
curl -sfL https://get.k3s.io | K3S_URL=https://10.0.0.10:6443 K3S_TOKEN="<取得したトークン>" sh -

動作確認

# Masterノードで全ノード確認
kubectl get nodes

期待される結果

NAME         STATUS   ROLES                  AGE     VERSION
k3s-master   Ready    control-plane,master   10m     v1.33.6+k3s1
k3s-node01   Ready    <none>                 5m      v1.33.6+k3s1
k3s-node02   Ready    <none>                 2m      v1.33.6+k3s1

アプリケーションデプロイとサービス公開

Nginxデプロイメント作成

# デプロイメント作成
kubectl create deployment nginx --image=nginx

# 確認
kubectl get deployments
kubectl get pods

サービス公開(LoadBalancer)

# LoadBalancerタイプで公開
kubectl expose deployment nginx --port=80 --type=LoadBalancer

# サービス確認
kubectl get svc

出力例

NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
nginx        LoadBalancer   10.43.169.93   <pending>     80:31038/TCP   10s

注意点: - EXTERNAL-IP<pending>表示は正常(MetalLB等が未設定のため) - NodePort(この例では31038)経由でアクセス可能 - 全ノードのIP:NodePortでアクセスできる

外部アクセスの確認

アクセス方法

# 任意のノードIP:NodePortでアクセス
curl http://192.168.100.20:31038  # Masterノード
curl http://192.168.100.21:31038  # Worker1ノード
curl http://192.168.100.22:31038  # Worker2ノード

発生したトラブルと解決方法

1. カーネルモジュール問題

現象

modprobe: FATAL: Module br_netfilter not found
modprobe: FATAL: Module overlay not found

原因:LXCコンテナではホストカーネルのモジュールにアクセスできない

解決法:Proxmoxホスト側でモジュール読み込み(前述)

2. UserNamespace問題

現象

Error: failed to run Kubelet: failed to create kubelet: open /dev/kmsg: no such file or directory

原因:LXC環境でのcgroup制限

解決法feature-gates=KubeletInUserNamespace=true設定(前述)

3. APIサーバー接続拒否

現象

The connection to the server 127.0.0.1:6443 was refused

原因:k3sサービスの起動失敗または完全な初期化前のアクセス

解決法

  1. サービス状態確認:systemctl status k3s
  2. ログ確認:journalctl -u k3s -f
  3. 起動完了まで待機(通常1-2分)

4. ネットワーク疎通問題

現象:Workerノードのjoinが完了しない

原因

解決法

# ポート確認
ss -tlnp | grep 6443

# 疎通確認
nc -zv <master-ip> 6443

# ファイアウォール無効化テスト
ufw disable

運用上の考慮事項

リソース監視

# ノードリソース確認
kubectl top nodes

# Pod単位のリソース確認
kubectl top pods

ログ確認

# Pod ログ
kubectl logs <pod-name>

# サービスログ
journalctl -u k3s -f

バックアップ

# etcdバックアップ(k3sではSQLiteの場合)
cp /var/lib/rancher/k3s/server/db/state.db /backup/

学んだこと・今後の展開

技術的収穫

  1. LXC環境での制約理解カーネルモジュールやcgroup制限への対処法を習得
  2. Kubernetes基礎:Pod、Service、Deploymentの実践的理解
  3. ネットワーク設計クラスター内部ネットワークと外部公開の仕組み
  4. トラブルシューティング:ログ分析とシステムデバッグ能力の向上

今後の活用予定

  1. アプリケーション開発:マイクロサービスアーキテクチャの実践
  2. CI/CD構築:GitOps による自動デプロイ環境
  3. 監視システム:Prometheus + Grafana の導入
  4. ストレージ管理:PersistentVolume を使用したデータ永続化

まとめ

ProxmoxのLXC環境でのK3sクラスター構築は、いくつかの制約があるものの、適切な設定により安定動作させることができます。特にLXC固有の制限(カーネルモジュールアクセス、UserNamespace)への対処が重要ですが、一度理解すれば再現性の高い環境構築が可能です。

自宅ラボでKubernetesを学習する環境としては、クラウドサービスと比較してコスト面で大きなメリットがあり、実践的なインフラ運用スキルの習得に適しています。


参考

PostgreSQLのインデックスについて深掘り

きっかけ

PostgreSQLで大文字小文字を区別しない文字列比較を行う方法という記事を読んで、citextという型(EXTENSION)やLOWER()を使った式インデックスについて知った。

記事自体は非常に分かりやすく、実用的な内容で完結していたので読みながら浮かんだいくつかの疑問について深堀していくことにした。

  • PostgreSQLには他にも面白い型やインデックスがあるのだろうか
  • 文字列のインデックスは日本語だとどう処理されるのか
  • 式インデックスの仕組み

記事とは別の角度から、これらの疑問をClaude(生成AI)との対話を通じて調べてみることにした。

調査過程と発見

疑問1: 他の面白い型とインデックスはあるか

調査方法: PostgreSQL公式ドキュメントベースで生成AIに質問

発見した興味深い型:

興味深いインデックス:

  • GIN: jsonb、配列、全文検索に最適
  • GiST: 地理空間、範囲検索、近似検索
  • BRIN: 非常に大きなテーブルの範囲検索
  • hash: 等価検索専用、非常に高速

疑問2: 日本語でのインデックス処理

調査結果:

  • UTF-8では1文字1-4バイト → インデックスサイズ確実に増大
  • Collation(ja_JP.UTF-8)が日本語ソート順に影響
  • 全文検索にはpg_trgm(トライグラム)や専用の日本語形態素解析が必要

疑問3: 数値にもGINは使える?

意外な発見: GINは数値の等価検索には使えるが、範囲検索(BETWEEN><)には向かない。数値配列の検索では威力を発揮。

-- 適用例:数値配列の検索
CREATE INDEX idx_tags_gin ON articles USING gin (tag_ids);
SELECT * FROM articles WHERE tag_ids @> ARRAY[42];

疑問4: ハッシュインデックスとカーディナリティの関係

当初の理解: ハッシュは高カーディナリティ向け 実際: カーディナリティに関係なく、等価検索専用なら最適

低カーディナリティ(status: 'pending', 'completed'など)でもハッシュインデックスは有効。

疑問5: 式インデックスの仕組み

理解: 事前に全行で式を計算し、その結果にインデックスを作成

-- LOWER(name)を全行で事前計算してインデックス化
CREATE INDEX idx_name_lower ON users (LOWER(name));

INSERT/UPDATE時に計算コストがかかるが、検索時は高速。

疑問6: BRIN

BRINについてはあまりふれてこなかった記憶があるのでこれを機に調べてみる。

64.5. BRINインデックス

ドキュメントを見ても、何がうれしいのかよくわからなかった。

シンプル故に非常に大きなテーブルになった際にBtreeなどよりも軽量になる?

PostgreSQLでパフォーマンスチューニングする時の初手はインデックス

BRINインデックスはかなり軽量なインデックスであるため、巨大なインデックスの代替手段として検討すると良いです。 ただし効果が最大限発揮されるテーブルには以下のような特徴が必要なため、利用場面は限られてきます。 1. データが物理的に挿入順や時系列順に並んでいる(履歴テーブルなど主に追記型のテーブル) 2. 非常に大きなテーブル(1000万件超) 引用元: PostgreSQLでパフォーマンスチューニングする時の初手はインデックス

学んだことと今後の探究

今回の収穫

【技術的収穫】

  • PostgreSQLの型システムの豊富さ
  • インデックス選択の判断基準の明確化
  • 日本語処理における注意点の把握

【調査手法の収穫】

  • 生成AIとの対話による効率的な技術調査
  • 疑問の連鎖から新たな学びを得る方法
  • 実装例を交えた理解の深化

今後深掘りしたいテーマ

全文検索の効率について

形態素解析によるインデックス作成とn-gramによる分割インデックスを特定の条件下で性能比較したい。

具体的には: - pgroonga (形態素解析) vs pg_trgm (トライグラム) の検索精度・速度比較 - pgroonga,pg_trgm以外も考えてる。 - 日本語特有の表記揺れ(ひらがな・カタカナ・漢字)への対応力 - インデックスサイズと検索性能のトレードオフ

また、それぞれのインデックスに対する運用レベルでの小技や最適化手法も実際に試してみたい。


参考文献

実行計画可視化ツール「pev2」でPostgreSQLのパフォーマンス最適化を学ぶ

参考

実行計画を可視化する「pev2」を使ってパフォーマンスチューニングを始めてみよう!

はじめに

この記事はハンズオンを意識したpev2の紹介記事。この記事を一通り見て、pev2の使い方についてある程度の知識を得ることができた。

また、いくつかの疑問について生成AIにて生成し、私が調査考察した上で回答し実際どうだったかを生成AIによって添削した。

学習内容のQ&A

Q1: 実行計画を読む際、どの項目を最初に注目すべきか?

A1: 実行時間

  • コストは推定値で実際の性能と乖離する場合がある
  • 実際の実行時間が最も信頼できる指標

実行時間とコストの両方を状況に応じて使い分け

実際の検証結果、開発環境と本番環境でハードウェア性能が異なる場合、実行時間だけでは判断できないケースが多い

  • 開発環境: 実行時間重視(実際のボトルネック特定)
  • 本番環境設計時: コスト重視(相対的な効率性評価)
  • 統計情報更新後: 両方の乖離をチェック

pev2では両方を同時に可視化できるため、併用することが重要。

Q2: B-Treeインデックスの複数カラム順序の決定基準は?

A2: 連番ライク(選択性の高い)なものを前に配置

  • ランダム性の高いカラムだと効果が薄れる
  • 絞り込み効果の大きいカラムを優先

クエリパターンを最優先に考慮

選択性だけでは不十分であることが実際の検証で判明。PostgreSQL公式ドキュメントでも以下の順序を推奨:

  1. 等価条件で使用されるカラムを先頭に
  2. 使用頻度の高いカラムを優先
  3. 範囲条件のカラムを後方に配置
-- 例:WHERE status = 'active' AND created_at > '2024-01-01'
-- statusの選択性が低くても、等価条件のため先頭に配置
CREATE INDEX idx_status_created ON orders (status, created_at);

実際に記事中でpev2で確認したものでは、この順序の方がIndex Condition部分の効率が良い結果となっている。

Q3: Index Only ScanとIndex Scanの違いと発生条件は?

A3: 検索・取得する全カラムがインデックスでカバーされている場合にIndex Only Scanが発生

  • テーブルへのアクセスが不要となる
  • 例外もあるが基本的にはOnly Scanで完了

【補強】VISIBILITYマップの影響を追記

Index Only Scanが実際に効果的になるための条件を検証で確認:

  • インデックスカバリング: 必要な全カラムがインデックスに含まれる
  • VISIBILITYマップ: テーブルのVACUUM状況に依存
  • 統計情報の精度: プランナーの判断材料
-- 実際の検証例
EXPLAIN (ANALYZE, BUFFERS) 
SELECT user_id, created_at FROM orders WHERE status = 'active';

-- Index Only Scan成功時:Heap Fetches: 0
-- Index Scanにフォールバック時:Heap Fetches: > 0

pev2ではHeap Fetchesの値で実際の動作を確認できる。

Q4: EXPLAINオプションの使い分けは?(VERBOSE,WAL,BUFFERのみ)

A4: 目的に応じて使い分け

  • VERBOSE: 詳細情報
  • WAL: WALレコード生成に関する情報
  • BUFFERS: バッファの使用状態

【詳細化】各オプションの具体的な活用場面

実際の運用での使い分けパターンを整理:

VERBOSE: - 出力カラムの詳細確認 - フィルター条件の内部処理確認 - JOINキーの詳細分析

BUFFERS: - I/O性能問題の特定 - キャッシュヒット率の確認 - ストレージアクセス最適化

WAL: - INSERT/UPDATE/DELETE文の性能分析 - バッチ処理の最適化 - レプリケーション負荷の予測

pev2では特にBUFFERSオプションの可視化が効果的で、Shared Hit/Read/Writtenの比率が一目で分かる。

Q5: 統計情報がプランナに与える影響は?

A5: 統計情報のズレは実行計画に大きく影響

  • プランナは統計情報を基に実行計画を組み立て
  • ズレが大きいほど非効率な計画が作られる可能性が高くなる

【具体例追加】統計情報更新の実際の効果

検証で確認した具体的なケース:

-- 統計情報更新前:Seq Scan選択
-- 更新後:Index Scan選択
ANALYZE orders;

-- pev2で比較すると実行時間が1/10に改善

特に以下の状況で統計情報の影響が顕著:

  • 大量データ投入後
  • データ分布の大幅変更後
  • 新しいインデックス作成後

pev2の「Rows」の推定値と実際値の乖離で統計情報の精度を判断できる。

Q6: JOINとWHEREの実行順序(内部処理)は?

A6: プランナの最適化によりWHERE→JOINの順で処理される場合がある

  • 論理的順序はJOIN→WHEREだが、内部実行順序は異なる
  • 今回のケースでは日付絞り込み→結合の流れで最適化されている

JOINアルゴリズムによる処理順序の違い

実際の検証で「WHERE→JOIN」という単純化は不正確であることが判明:

Hash Join: - 小さいテーブル(ビルド側)を先にスキャン - WHERE条件は可能な限りJOIN前に適用(プッシュダウン)

Nested Loop: - 外側テーブルの各行に対して内側テーブルをスキャン - WHERE条件の適用タイミングが複雑

Merge Join: - 両テーブルをソート済み順序でスキャン - ソートキーに関連するWHERE条件が特に重要

-- pev2で実際のJOINアルゴリズムと条件適用順序を確認
EXPLAIN (ANALYZE, BUFFERS) 
SELECT * FROM orders o 
JOIN customers c ON o.customer_id = c.id 
WHERE o.created_at > '2024-01-01' AND c.status = 'active';

pev2では各JOINノードでの条件適用状況が視覚的に確認できる。

まとめ

生成AIの出してきた質問自体はpev2とはかなり関係のないものだった。

しかし、postgresql自体の理解を深めることができたので、やってよかったとは思う。

2025年11月振り返り

投稿状況

投稿日数:21/30日

 月  火  水  木  金  土  日
[×][●][×][●][●][×][●] Week 1
[●][●][●][●][●][●][×] Week 2  
[×][●][×][×][●][●][×] Week 3
[●][●][●][●][●][●][●] Week 4
[×][×][●][●]            Week 5

● = 投稿あり  × = 投稿なし

曜日別投稿率:

  • 月曜日:2/4回 (50%)
  • 火曜日:4/5回 (80%)
  • 水曜日:2/4回 (50%)
  • 木曜日:4/4回 (100%)
  • 金曜日:5/5回 (100%)
  • 土曜日:3/4回 (75%)
  • 日曜日:1/4回 (25%)

前月(23/31日、74%)から減少(21/30日、70%)。

全体的なパターン

チェックリストの導入と変遷

  • 11/2-11/16:詳細なチェックリスト運用(14項目)
  • 11/15以降:「技術記事を読む」が「自宅インフラ作業」に変更
  • 完了率の変動:好調時(11/2-11/5、11/8-11/11)と不調時(11/7、11/13-11/14、11/26-11/30)が明確

メンタル状態の波

  • 好調期:11/2-11/5、11/8-11/11、11/19-11/25
  • 不調期:11/7(「急にメンタルに来た」)、11/13-11/14、11/26-11/30(未記入増加)
  • 特徴:不調期は「うっせえええええ」「だめだめだよ」など感情的な記述が増加

生活習慣の安定化

  • 筋トレ:メニュー見直し(11/4)、分割・優先度制導入(11/9)
  • 食事管理:あすけん継続、カロリーオーバーへの言及増加
  • ウォーキング:実施日は8000歩-10000歩を達成

主要な取り組み・進捗

技術関連

  • 自宅インフラ:Proxmox + ELK監視構築への取り組み(月中旬から本格化)
  • LeetCode:継続実施、Easy問題数秒完了の日も
  • 技術記事:Zenn投稿継続(11/20、11/28言及)
  • BGM Mixer開発:月末に生成AI活用でゲーム制作

生活改善の試み

  • 筋トレメニュー改善

    • 11/4:種類増加(臀部、腹筋追加)
    • 11/9:優先度・分割メニュー導入
    • 結果:負荷過多による実施困難→調整の必要性認識
  • 習慣管理の見直し

    • 消耗品チェック追加(11/9)
    • SNS投稿ルール変更(はてなブログ継続、X投稿停止、Zennのみ通知)

外部活動

  • 出社:11/10に久々出社、年末調整・相談実施
  • 外出・社交:11/22に飲み会参加(その後タリーズで作業)

課題

継続的な課題

  1. 起床・朝の行動問題

    • 「朝遅かった」「朝だめ」の記述継続
    • 朝タスク実行の困難さ持続
  2. メンタル状態の不安定性

    • 11/7:「急にメンタルに来た」
    • 11/13-14:「うっせえええ」「だめだめ」
    • 11/26-30:記入停止
  3. 食事管理の課題

    • カロリーオーバーの頻発
    • 11/8:「1500キロカロリーオーバー」「ケンタッキー」
    • 酒・外食による計画破綻

新たな発見・課題

筋トレメニューの過負荷問題

11/4にメニュー拡張→11/7に実施困難→調整の必要性を認識。「やはり増やしたからか?」(11/7)

仕事ストレスの影響

「仕事がうまくいってないからもやもやする」(11/19)、トラブルシューティング継続言及

11月の成果

ポジティブな変化

  1. 自宅インフラ構築の本格化:月中旬からProxmox環境整備
  2. チェックリスト運用の確立:詳細な進捗管理手法の導入
  3. 技術記事投稿の継続:Zenn等への定期投稿維持
  4. 创作活動:BGM Mixerゲーム開発(生成AI活用)

継続的強み

  1. 最小実行の維持:不調時も部分的にタスク実施
  2. 自己調整能力:筋トレメニュー過負荷を認識し調整
  3. 技術学習の継続:LeetCode、インフラ作業の継続実施

12月への提言

1. メンタル状態管理の重要性

11月後半の記入停止を踏まえ:

  • ミニマムタスクの設定:不調時でも継続可能な最小限メニュー
  • 仕事ストレス対処トラブルシューティング等の業務負荷軽減策検討
  • 記録の簡素化:不調時でも記入可能な簡易フォーマット準備

2. 筋トレメニューの最適化

11月の試行錯誤を活かし:

  • 段階的拡張:一度に複数項目追加せず、1つずつ検証
  • 疲労度指標:実施後の疲労感を数値化して適量判断
  • 回復日設定:完全休息日の明確化

3. 習慣の優先順位明確化

チェックリスト14項目の見直し:

  • コア習慣:絶対維持(筋トレ、LeetCode、技術記事等)
  • 調整可能習慣:不調時スキップ許可(瞑想、外気等)
  • 実験的習慣:効果測定後継続判断

4. 時期的配慮

年末年始を踏まえた現実的な目標設定:

  • 業務負荷:年末の繁忙期考慮
  • 生活リズム:年末年始の不規則性受容
  • 目標調整:1月からの本格始動を見据えた準備期間として位置付け

まとめ

11月は自宅インフラ構築やゲーム開発等の創作活動で成果を上げた一方、メンタル状態の不安定性と筋トレメニュー過負荷が主要課題として浮上。

ブログ運営の振り返りと方針転換

スライドを見て感じたこと

speakerdeck.com

このスライドを読み、ここ最近ほぼ毎日投稿してきた記事を振り返った。記事の感想やメモと合わせていくつか痛感した点を挙げていく。

手元で動作確認なしのコード掲載

これは完全に自分の記事に当てはまっていた。コードを実際に動かさず掲載していた点は明確に問題だった。

技術的判断の丸投げ

Docker環境を実際に構築して動作確認した上での情報共有なら問題ないと考えている。しかし、ソースも示さずドキュメントらしきものから書き起こした情報の羅列には価値がない。

わからないことを生成AIに聞いて、その結果をそのまま貼り付けるだけ。「やりました」という証以外に何の意味があるのか。

THINK BIGGER

https://www.amazon.co.jp/THINK-BIGGER-%E3%80%8C%E6%9C%80%E9%AB%98%E3%81%AE%E7%99%BA%E6%83%B3%E3%80%8D%E3%82%92%E7%94%9F%E3%82%80%E6%96%B9%E6%B3%95%EF%BC%9A%E3%82%B3%E3%83%AD%E3%83%B3%E3%83%93%E3%82%A2%E5%A4%A7%E5%AD%A6%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E3%82%B9%E3%82%AF%E3%83%BC%E3%83%AB%E7%89%B9%E5%88%A5%E8%AC%9B%E7%BE%A9-%E3%82%B7%E3%83%BC%E3%83%8A%E3%83%BB%E3%82%A2%E3%82%A4%E3%82%A8%E3%83%B3%E3%82%AC%E3%83%BC/dp/491006334X

そういう本があるらしい。今のところスライドの内容以上に興味はないので頭の片隅においておくことにした。

スライドで説明されている内容からいくつか取り上げる。

2〜3日で解決するくらいの問題を見つける

この考え方に沿うなら、一日一記事の投稿はほぼ不可能だ。生成AIではなく人間が実際に経験したことを記事にするには、最低でも2〜3日は必要だということを理解した。

ジャムの法則

seeds-create.co.jp

ジャムの法則(Jam study)とは、1995年にコロンビア大学に所属するシーナ・アイエンガー教授が発表した法則で、人間の選択肢に対する行動のことで、検討できる選択肢が増えると逆に選択が難しくなるという法則のことです。

つまり選択肢が多すぎると人はかえって決断が難しくなり意思決定を避けてしまうということ。

記事の質より量を優先していた自分の姿勢と重なった。

個人ブログ故にすべてを参考にはしない

参考になる部分は多いが、私は個人ブログのためフォーマットなどは生成AIに任せる方針。スライドの内容は6割程度を参考にする。


このブログについて

これまでのブログ運営

前提として、生成AIによる記事投稿を続けてきたことは後悔していない。

記事作成の手法は以下の通りだった:

  • 経験部分はなるべく自分に沿ったものにする
  • 記事から質問を生成してもらう
  • 対話形式で答える
  • それを記事化する

ただし、この手法には明確な問題があった。スライドで指摘されていた手元で動作確認なしのコード掲載に該当していた上、生成AIへの依存度が高すぎた。

もちろん、他者に迷惑をかけるつもりは最初からない。自分の成長のために一定期間アクションを起こし、その結果「失敗だった」と気づけたことは良かったと言える。

当初は成長のため生成AI主体で続けるつもりだった。しかし、これ以上継続すると完全に生成AIへの丸投げになる。それは無理だという結論に至った。ある意味、スライドがトドメを刺した。

これからのブログ運営

更新頻度: 週1回で様子を見る

生成AIの使い方見直し:

  • 文章の大本は自分で書く
  • 図の生成については真剣に取り組む(生成AIは補助的に使用)