mcpField
P
postgresql-optimization

postgresql-optimization

github.com/githubデータ・データベース40.5k16.6k 回インストール今日更新
リポジトリ

postgresql-optimization について

PostgreSQL のクエリ性能を分析し、データベース固有の機能を活用するための最適化ガイドスキルです。クエリパターン、インデックス、監視、保守、セキュリティ確認を、実行可能な SQL 例とともに扱います。

主な機能

  1. 01クエリと実行計画の分析
  2. 02複合・部分・式インデックスの選択
  3. 03JSONB、配列、ウィンドウ関数の活用
  4. 04接続、クエリ、データベース容量の監視
  5. 05セキュリティ、保守、性能の確認

活用シーン

  1. 01低速クエリや非効率なスキャンの調査
  2. 02頻出条件に合わせたインデックス設計
  3. 03JSONB クエリとページネーションの最適化
  4. 04データベースの監視と保守の計画

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/github/awesome-copilot --skill postgresql-optimization

インストール後、Claude Code で/postgresql-optimizationを入力して読み込まれたか確認します。

詳細

PostgreSQL 開発アシスタント

${selection}(選択範囲がない場合はプロジェクト全体)に対する PostgreSQL の専門的なガイダンスです。PostgreSQL 固有の機能、最適化パターン、高度な機能に焦点を当てます。

� PostgreSQL 固有の機能

JSONB 操作
-- Advanced JSONB queries
CREATE TABLE events (
    id SERIAL PRIMARY KEY,
    data JSONB NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- GIN index for JSONB performance
CREATE INDEX idx_events_data_gin ON events USING gin(data);

-- JSONB containment and path queries
SELECT * FROM events 
WHERE data @> '{"type": "login"}'
  AND data #>> '{user,role}' = 'admin';

-- JSONB aggregation
SELECT jsonb_agg(data) FROM events WHERE data ? 'user_id';
配列操作
-- PostgreSQL arrays
CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    tags TEXT[],
    categories INTEGER[]
);

-- Array queries and operations
SELECT * FROM posts WHERE 'postgresql' = ANY(tags);
SELECT * FROM posts WHERE tags && ARRAY['database', 'sql'];
SELECT * FROM posts WHERE array_length(tags, 1) > 3;

-- Array aggregation
SELECT array_agg(DISTINCT category) FROM posts, unnest(categories) as category;
ウィンドウ関数と分析
-- Advanced window functions
SELECT 
    product_id,
    sale_date,
    amount,
    -- Running totals
    SUM(amount) OVER (PARTITION BY product_id ORDER BY sale_date) as running_total,
    -- Moving averages
    AVG(amount) OVER (PARTITION BY product_id ORDER BY sale_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as moving_avg,
    -- Rankings
    DENSE_RANK() OVER (PARTITION BY EXTRACT(month FROM sale_date) ORDER BY amount DESC) as monthly_rank,
    -- Lag/Lead for comparisons
    LAG(amount, 1) OVER (PARTITION BY product_id ORDER BY sale_date) as prev_amount
FROM sales;
全文検索
-- PostgreSQL full-text search
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    title TEXT,
    content TEXT,
    search_vector tsvector
);

-- Update search vector
UPDATE documents 
SET search_vector = to_tsvector('english', title || ' ' || content);

-- GIN index for search performance
CREATE INDEX idx_documents_search ON documents USING gin(search_vector);

-- Search queries
SELECT * FROM documents 
WHERE search_vector @@ plainto_tsquery('english', 'postgresql database');

-- Ranking results
SELECT *, ts_rank(search_vector, plainto_tsquery('postgresql')) as rank
FROM documents 
WHERE search_vector @@ plainto_tsquery('postgresql')
ORDER BY rank DESC;

� PostgreSQL のパフォーマンスチューニング

クエリの最適化
-- EXPLAIN ANALYZE for performance analysis
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) 
SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2024-01-01'::date
GROUP BY u.id, u.name;

-- Identify slow queries from pg_stat_statements
SELECT query, calls, total_time, mean_time, rows,
       100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements 
ORDER BY total_time DESC 
LIMIT 10;
インデックス戦略
-- Composite indexes for multi-column queries
CREATE INDEX idx_orders_user_date ON orders(user_id, order_date);

-- Partial indexes for filtered queries
CREATE INDEX idx_active_users ON users(created_at) WHERE status = 'active';

-- Expression indexes for computed values
CREATE INDEX idx_users_lower_email ON users(lower(email));

-- Covering indexes to avoid table lookups
CREATE INDEX idx_orders_covering ON orders(user_id, status) INCLUDE (total, created_at);
接続とメモリの管理
-- Check connection usage
SELECT count(*) as connections, state 
FROM pg_stat_activity 
GROUP BY state;

-- Monitor memory usage
SELECT name, setting, unit 
FROM pg_settings 
WHERE name IN ('shared_buffers', 'work_mem', 'maintenance_work_mem');

�️ PostgreSQL の高度なデータ型

カスタム型とドメイン
-- Create custom types
CREATE TYPE address_type AS (
    street TEXT,
    city TEXT,
    postal_code TEXT,
    country TEXT
);

CREATE TYPE order_status AS ENUM ('pending', 'processing', 'shipped', 'delivered', 'cancelled');

-- Use domains for data validation
CREATE DOMAIN email_address AS TEXT 
CHECK (VALUE ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$');

-- Table using custom types
CREATE TABLE customers (
    id SERIAL PRIMARY KEY,
    email email_address NOT NULL,
    address address_type,
    status order_status DEFAULT 'pending'
);
範囲型
-- PostgreSQL range types
CREATE TABLE reservations (
    id SERIAL PRIMARY KEY,
    room_id INTEGER,
    reservation_period tstzrange,
    price_range numrange
);

-- Range queries
SELECT * FROM reservations 
WHERE reservation_period && tstzrange('2024-07-20', '2024-07-25');

-- Exclude overlapping ranges
ALTER TABLE reservations 
ADD CONSTRAINT no_overlap 
EXCLUDE USING gist (room_id WITH =, reservation_period WITH &&);
幾何データ型
-- PostgreSQL geometric types
CREATE TABLE locations (
    id SERIAL PRIMARY KEY,
    name TEXT,
    coordinates POINT,
    coverage CIRCLE,
    service_area POLYGON
);

-- Geometric queries
SELECT name FROM locations 
WHERE coordinates <-> point(40.7128, -74.0060) < 10; -- Within 10 units

-- GiST index for geometric data
CREATE INDEX idx_locations_coords ON locations USING gist(coordinates);

📊 PostgreSQL の拡張機能とツール

便利な拡張機能
-- Enable commonly used extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";    -- UUID generation
CREATE EXTENSION IF NOT EXISTS "pgcrypto";     -- Cryptographic functions
CREATE EXTENSION IF NOT EXISTS "unaccent";     -- Remove accents from text
CREATE EXTENSION IF NOT EXISTS "pg_trgm";      -- Trigram matching
CREATE EXTENSION IF NOT EXISTS "btree_gin";    -- GIN indexes for btree types

-- Using extensions
SELECT uuid_generate_v4();                     -- Generate UUIDs
SELECT crypt('password', gen_salt('bf'));      -- Hash passwords
SELECT similarity('postgresql', 'postgersql'); -- Fuzzy matching
監視とメンテナンス
-- Database size and growth
SELECT pg_size_pretty(pg_database_size(current_database())) as db_size;

-- Table and index sizes
SELECT schemaname, tablename,
       pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
FROM pg_tables 
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;

-- Index usage statistics
SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_user_indexes 
WHERE idx_scan = 0;  -- Unused indexes
PostgreSQL 固有の最適化のヒント
  • EXPLAIN (ANALYZE, BUFFERS) を使用する:詳細なクエリ分析のため
  • postgresql.conf を設定する:ワークロードに合わせて(OLTP か OLAP か)
  • コネクションプーリングを使用する(pgbouncer):高並行性のアプリケーション向け
  • 定期的な VACUUM と ANALYZE:最適なパフォーマンスのため
  • 大きなテーブルをパーティション化する:PostgreSQL 10 以降の宣言的パーティショニングを使用
  • pg_stat_statements を使用する:クエリのパフォーマンス監視のため

📊 監視とメンテナンス

クエリパフォーマンスの監視
-- Identify slow queries
SELECT query, calls, total_time, mean_time, rows
FROM pg_stat_statements 
ORDER BY total_time DESC 
LIMIT 10;

-- Check index usage
SELECT schemaname, tablename, indexname, idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_user_indexes 
WHERE idx_scan = 0;
データベースのメンテナンス
  • VACUUM と ANALYZE:パフォーマンスのための定期的なメンテナンス
  • インデックスのメンテナンス:断片化したインデックスを監視して再構築する
  • 統計情報の更新:クエリプランナの統計情報を最新に保つ
  • ログ分析:PostgreSQL のログを定期的に確認する

🛠️ 一般的なクエリパターン

ページネーション
-- ❌ BAD: OFFSET for large datasets
SELECT * FROM products ORDER BY id OFFSET 10000 LIMIT 20;

-- ✅ GOOD: Cursor-based pagination
SELECT * FROM products 
WHERE id > $last_id 
ORDER BY id 
LIMIT 20;
集計
-- ❌ BAD: Inefficient grouping
SELECT user_id, COUNT(*) 
FROM orders 
WHERE order_date >= '2024-01-01' 
GROUP BY user_id;

-- ✅ GOOD: Optimized with partial index
CREATE INDEX idx_orders_recent ON orders(user_id) 
WHERE order_date >= '2024-01-01';

SELECT user_id, COUNT(*) 
FROM orders 
WHERE order_date >= '2024-01-01' 
GROUP BY user_id;
JSON クエリ
-- ❌ BAD: Inefficient JSON querying
SELECT * FROM users WHERE data::text LIKE '%admin%';

-- ✅ GOOD: JSONB operators and GIN index
CREATE INDEX idx_users_data_gin ON users USING gin(data);

SELECT * FROM users WHERE data @> '{"role": "admin"}';

📋 最適化チェックリスト

クエリ分析
  • 負荷の高いクエリに対して EXPLAIN ANALYZE を実行する
  • 大きなテーブルでのシーケンシャルスキャンを確認する
  • 適切な結合アルゴリズムであることを検証する
  • WHERE 句の選択性を確認する
  • ソートおよび集計の操作を分析する
インデックス戦略
  • 頻繁にクエリされる列にインデックスを作成する
  • 複数列の検索には複合インデックスを使用する
  • フィルタ付きクエリには部分インデックスを検討する
  • 未使用または重複したインデックスを削除する
  • インデックスの膨張と断片化を監視する
セキュリティレビュー
  • パラメータ化クエリのみを使用する
  • 適切なアクセス制御を実装する
  • 必要な箇所で行レベルのセキュリティを有効にする
  • 機密データへのアクセスを監査する
  • 安全な接続方法を使用する
パフォーマンス監視
  • クエリパフォーマンスの監視を設定する
  • 適切なログ設定を行う
  • コネクションプールの使用状況を監視する
  • データベースの増加とメンテナンスのニーズを追跡する
  • パフォーマンス低下に対するアラートを設定する

🎯 最適化の出力形式

クエリ分析結果
## Query Performance Analysis

**Original Query**:
[Original SQL with performance issues]

**Issues Identified**:
- Sequential scan on large table (Cost: 15000.00)
- Missing index on frequently queried column
- Inefficient join order

**Optimized Query**:
[Improved SQL with explanations]

**Recommended Indexes**:
```sql
CREATE INDEX idx_table_column ON table(column);

パフォーマンスへの影響:実行時間が 80% 改善される見込み


## 🚀 Advanced PostgreSQL Features

### Window Functions
```sql
-- Running totals and rankings
SELECT 
    product_id,
    order_date,
    amount,
    SUM(amount) OVER (PARTITION BY product_id ORDER BY order_date) as running_total,
    ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY amount DESC) as rank
FROM sales;
共通テーブル式(CTE)
-- Recursive queries for hierarchical data
WITH RECURSIVE category_tree AS (
    SELECT id, name, parent_id, 1 as level
    FROM categories 
    WHERE parent_id IS NULL
    
    UNION ALL
    
    SELECT c.id, c.name, c.parent_id, ct.level + 1
    FROM categories c
    JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT * FROM category_tree ORDER BY level, name;

PostgreSQL の高度な機能を活用しながら、クエリのパフォーマンス、セキュリティ、保守性を向上させる、具体的で実行可能な PostgreSQL の最適化を提供することに焦点を当てます。

コメント