2026年2月22日日曜日

AI ワークロードのための MySQL + Neo4j:なぜリレーショナルデータベースが今なお重要か

This article was originally published in English at AnotherMySQLDBA.

AIエージェント用の永続メモリを構築する方法を、既にお使いのデータベースを使って文書化する時期が来たと考えました。ベクトルデータベースではありません - MySQLとNeo4jです。

これは理論ではありません。私はこのアーキテクチャを日常的に使用し、複数のプロジェクトでAIエージェントのメモリを管理しています。実際に機能するスキーマとクエリパターンを紹介します。

アーキテクチャ

AIエージェントには2種類のメモリが必要です:

  • 構造化メモリ - 何が起こったか、いつ、なぜ(MySQL)
  • パターンメモリ - 何が何に繋がっているか(Neo4j)

ベクトルデータベースは類似性検索用です。ワークフローの状態や決定履歴を追跡するには適していません。それにはACIDトランザクションと適切なリレーションシップが必要です。

MySQLスキーマ

AIエージェントの永続メモリのための実際のスキーマはこちらです:

-- Architecture decisions the AI made
CREATE TABLE architecture_decisions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    project_id INT NOT NULL,
    title VARCHAR(255) NOT NULL,
    decision TEXT NOT NULL,
    rationale TEXT,
    alternatives_considered TEXT,
    status ENUM('accepted', 'rejected', 'pending') DEFAULT 'accepted',
    decided_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    tags JSON,
    INDEX idx_project_date (project_id, decided_at),
    INDEX idx_status (status)
) ENGINE=InnoDB;

-- Code patterns the AI learned
CREATE TABLE code_patterns (
    id INT AUTO_INCREMENT PRIMARY KEY,
    project_id INT NOT NULL,
    category VARCHAR(50) NOT NULL,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    code_example TEXT,
    language VARCHAR(50),
    confidence_score FLOAT DEFAULT 0.5,
    usage_count INT DEFAULT 0,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_project_category (project_id, category),
    INDEX idx_confidence (confidence_score)
) ENGINE=InnoDB;

-- Work session tracking
CREATE TABLE work_sessions (
    id INT AUTO_INCREMENT PRIMARY KEY,
    session_id VARCHAR(255) UNIQUE NOT NULL,
    project_id INT NOT NULL,
    started_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    ended_at DATETIME,
    summary TEXT,
    context JSON,
    INDEX idx_project_session (project_id, started_at)
) ENGINE=InnoDB;

-- Pitfalls to avoid (learned from mistakes)
CREATE TABLE pitfalls (
    id INT AUTO_INCREMENT PRIMARY KEY,
    project_id INT NOT NULL,
    category VARCHAR(50),
    title VARCHAR(255) NOT NULL,
    description TEXT,
    how_to_avoid TEXT,
    severity ENUM('critical', 'high', 'medium', 'low'),
    encountered_count INT DEFAULT 1,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_project_severity (project_id, severity)
) ENGINE=InnoDB;

外部キー。チェック制約。適切なインデックス。これはリレーショナルデータベースが得意とするところです。

クエリパターン

AIエージェントのメモリを実際にクエリする方法はこちらです:

-- Get recent decisions for context
SELECT title, decision, rationale, decided_at
FROM architecture_decisions
WHERE project_id = ?
  AND decided_at > DATE_SUB(NOW(), INTERVAL 30 DAY)
ORDER BY decided_at DESC
LIMIT 10;

-- Find high-confidence patterns
SELECT category, name, description, code_example
FROM code_patterns
WHERE project_id = ?
  AND confidence_score >= 0.80
ORDER BY usage_count DESC, confidence_score DESC
LIMIT 20;

-- Check for known pitfalls before implementing
SELECT title, description, how_to_avoid
FROM pitfalls
WHERE project_id = ?
  AND category = ?
  AND severity IN ('critical', 'high')
ORDER BY encountered_count DESC;

-- Track session context across interactions
SELECT context
FROM work_sessions
WHERE session_id = ?
ORDER BY started_at DESC
LIMIT 1;

これらはストレートフォワードなSQLクエリです。EXPLAINで期待通りのインデックス使用が確認できます。サプライズはありません。

Neo4jレイヤー

MySQLが構造化データを扱い、Neo4jがリレーションシップを扱います:

// Create nodes for decisions
CREATE (d:Decision {
  id: 'dec_123',
  title: 'Use FastAPI',
  project_id: 1,
  embedding: [0.23, -0.45, ...]  // Vector for similarity
})

// Create relationships
CREATE (d1:Decision {id: 'dec_123', title: 'Use FastAPI'})
CREATE (d2:Decision {id: 'dec_45', title: 'Used Flask before'})
CREATE (d1)-[:SIMILAR_TO {score: 0.85}]->(d2)
CREATE (d1)-[:CONTRADICTS]->(d3:Decision {title: 'Avoid frameworks'})

// Query: Find similar past decisions
MATCH (current:Decision {id: $decision_id})
MATCH (current)-[r:SIMILAR_TO]-(similar:Decision)
WHERE r.score > 0.80
RETURN similar.title, r.score
ORDER BY r.score DESC

// Query: What outcomes followed this pattern?
MATCH (d:Decision)-[:LEADS_TO]->(o:Outcome)
WHERE d.title CONTAINS 'Redis'
RETURN d.title, o.type, o.success_rate

それらが連携して動作する仕組み

フローは以下のようになります:

  1. AIエージェントがコンテンツを生成するか決定を下す
  2. MySQLに構造化データを保存(何、いつ、なぜ、完全なコンテキスト)
  3. エンベディングを生成し、類似アイテムとのリレーションシップ付きでNeo4jに保存
  4. 次のセッション:Neo4jが関連する類似決定を見つけ出す
  5. MySQLがその決定の詳細情報を提供

MySQLが真実の源です。Neo4jがパターン発見者です。

なぜベクトルデータベースだけではダメなのか?

PineconeやWeaviateだけでAIエージェントのメモリを構築しようとするチームを見てきましたが、うまく行きません。理由は:

ベクトルDBが得意なこと:

  • クエリに似たドキュメントを見つける
  • セマンティック検索(RAG)
  • "これに似たもの"

ベクトルDBが苦手なこと:

  • "3月15日に何を決定したか?"
  • "障害を引き起こした決定を表示"
  • "このワークフローの現在の状態は?"
  • "confidence > 0.8 AND usage_count > 10のパターンはどれ?"

これらのクエリには構造化フィルタリング、結合、トランザクションが必要です。それはリレーショナルデータベースの領域です。

MCPと未来

Model Context Protocol (MCP)は、AIシステムがコンテキストを扱う方法を標準化しています。初期のMCP実装でも、私たちがすでに知っていたことが明らかになっています:構造化ストレージとグラフリレーションシップの両方が必要です。

``````html

MySQL は MCP の「resources」と「tools」カタログを扱います。Neo4j はコンテキスト項目間の「relationships」を扱います。ベクター埋め込みはパズルの一部に過ぎません。

Production Notes

このアーキテクチャを実行している現在のシステム:

  • MySQL 8.0, 48 tables, ~2GB data
  • Neo4j Community, ~50k nodes, ~200k relationships
  • Query latency: MySQL <10ms, Neo4j <50ms
  • Backup: Standard mysqldump + neo4j-admin dump
  • Monitoring: Same Percona tools I've used for years

運用上の複雑さは低いです。これらは成熟したデータベースで、よく理解された運用パターンを持っています。

When to Use What

Use CaseDatabase
Workflow state, decisions, audit trailMySQL/PostgreSQL
Pattern detection, similarity, relationshipsNeo4j
Semantic document search (RAG)Vector DB (optional)

状態には MySQL から始めましょう。パターン認識が必要になったら Neo4j を追加します。セマンティックドキュメント検索を実際にしている場合にのみ、ベクターデータベースを追加してください。

Summary

AI エージェントには永続的なメモリが必要です。単なるベクターデータベースの埋め込みではなく、構造化された、リレーショナルで、時間的なメモリにパターン認識を備えたものです。

MySQL は構造化された状態を扱います。Neo4j はグラフリレーションシップを扱います。これらを組み合わせることで、ベクターデータベース単独では提供できないものを提供します。

AI ワークロードのためにリレーショナルデータベースを放棄しないでください。それぞれの仕事に適したツールを使用し、それは両方を一緒に使うことです。

このアーキテクチャに関する AI エージェントの視点の詳細については、3k1o の関連投稿をご覧ください。

MySQL 8.0 JSON 関数:実践的な例とインデクシング

This article was originally published in English at AnotherMySQLDBA.

この投稿では、MySQL 8.0 の JSON 関数のハンズオン解説を扱います。JSON サポートは MySQL 5.7 から存在しますが、8.0 では重要な改善が追加されました — より優れたインデックス戦略、新しい関数、マルチバリューインデックス — これにより JSON データの取り扱いが大幅に実用的になりました。以下の内容では、最も一般的に必要なパターンのいくつかを文書化し、EXPLAIN の出力と知っておくべきパフォーマンス観察を含めています。

これは「JSON vs. リレーショナル」の議論投稿ではありません。MySQL に JSON を保存している場合、すでに理由をお持ちでしょう。ここでの目標は、利用可能なツールを効果的に使用していることを確認することです。

環境

mysql> SELECT @@version, @@version_comment\G
*************************** 1. row ***************************
        @@version: 8.0.36
@@version_comment: MySQL Community Server - GPL

テストは 8GB RAM の VM で行われ、innodb_buffer_pool_size を 4G に設定しました。言及する価値のあるメンテナンス上の注意点として:query_cache_type は 8.0 では無関係です。なぜなら query cache が完全に削除されたからです。5.7 インスタンスから移行し、my.cnf にその変数が残っている場合、削除してください — MySQL 8.0 は起動エラーを投げます。

テストテーブルの設定

テストテーブルは、かなり一般的なパターンをシミュレートしています — アプリケーションがユーザー profile データとイベントメタデータを JSON blob として保存するものです:

CREATE TABLE user_events (
  id          INT UNSIGNED NOT NULL AUTO_INCREMENT,
  user_id     INT UNSIGNED NOT NULL,
  event_data  JSON NOT NULL,
  created_at  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  INDEX idx_user (user_id)
) ENGINE=InnoDB;

INSERT INTO user_events (user_id, event_data) VALUES
(1, '{"action":"login","ip":"192.168.1.10","tags":["mobile","vpn"],"score":88}'),
(1, '{"action":"purchase","ip":"192.168.1.10","tags":["desktop"],"score":72,"amount":49.99}'),
(2, '{"action":"login","ip":"10.0.0.5","tags":["mobile"],"score":91}'),
(3, '{"action":"logout","ip":"10.0.0.9","tags":["desktop","vpn"],"score":65}'),
(2, '{"action":"purchase","ip":"10.0.0.5","tags":["mobile"],"score":84,"amount":129.00}');

基本的な抽出:JSON_VALUE vs. JSON_EXTRACT

JSON_VALUE() は MySQL 8.0.21 で導入され、スカラー値を抽出するよりクリーンな方法で、組み込みの型キャストが可能です。それ以前は JSON_EXTRACT()(または -> 省略形)を使用し、手動でキャストする必要があり、動作はしますがクエリにノイズを追加します。

-- Pre-8.0.21 approach
SELECT user_id,
       JSON_EXTRACT(event_data, '$.action') AS action,
       CAST(JSON_EXTRACT(event_data, '$.score') AS UNSIGNED) AS score
FROM user_events;

-- Cleaner 8.0.21+ approach
SELECT user_id,
       JSON_VALUE(event_data, '$.action') AS action,
       JSON_VALUE(event_data, '$.score' RETURNING UNSIGNED) AS score
FROM user_events;

2 番目のクエリの出力:

+---------+----------+-------+
| user_id | action   | score |
+---------+----------+-------+
|       1 | login    |    88 |
|       1 | purchase |    72 |
|       2 | login    |    91 |
|       3 | logout   |    65 |
|       2 | purchase |    84 |
+---------+----------+-------+
5 rows in set (0.00 sec)

RETURNING 句は本当に有用です。煩わしいダブルキャストパターンを排除し、後でクエリコードを読む際に意図を明確にします。

マルチバリューインデックス:真のゲームチェンジャー

ここが 8.0 で JSON ワークロードの本当の進化点です。MySQL 8.0.17 以降利用可能なマルチバリューインデックスにより、JSON カラム内の配列要素を直接インデックス付けできます。実際の動作は以下のようになります:

ALTER TABLE user_events
  ADD INDEX idx_tags ((CAST(event_data->'$.tags' AS CHAR(64) ARRAY)));

タグ値でフィルタリングするクエリに対する、EXPLAIN の前後を示します:

-- Without the multi-valued index:
EXPLAIN SELECT * FROM user_events
WHERE JSON_CONTAINS(event_data->'$.tags', '"vpn"')\G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user_events
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5
     filtered: 100.00
        Extra: Using where

-- After adding the multi-valued index:
EXPLAIN SELECT * FROM user_events
WHERE JSON_CONTAINS(event_data->'$.tags', '"vpn"')\G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user_events
   partitions: NULL
         type: range
possible_keys: idx_tags
          key: idx_tags
      key_len: 67
          ref: NULL
         rows: 2
     filtered: 100.00
        Extra: Using where

フルテーブルスキャンからレンジスキャンへ。5 行では些細なことですが、数百万行のテーブルで頻繁なタグベースのフィルタリングを行う場合、その差は顕著です。改善効果はテーブルサイズとクエリ頻度に比例してスケールします。

重要な注意点として:MEMBER OF()JSON_OVERLAPS() もマルチバリューインデックスから恩恵を受けますが、JSON_SEARCH() は受けません。設計時にクエリパターンを選択する際に重要です:

-- This WILL use the multi-valued index:
SELECT * FROM user_events
WHERE 'vpn' MEMBER OF (event_data->'$.tags');

-- This will NOT use it:
SELECT * FROM user_events
WHERE JSON_SEARCH(event_data->'$.tags', 'one', 'vpn') IS NOT NULL;

JSON の集計と変換

よく知っておくべきいくつかの集計関数:

``````html
-- Build a JSON array of actions per user
SELECT user_id,
       JSON_ARRAYAGG(JSON_VALUE(event_data, '$.action')) AS actions
FROM user_events
GROUP BY user_id;

+---------+----------------------+
| user_id | actions              |
+---------+----------------------+
|       1 | ["login","purchase"] |
|       2 | ["login","purchase"] |
|       3 | ["logout"]           |
+---------+----------------------+
3 rows in set (0.01 sec)

-- Summarize into a JSON object keyed by action
SELECT user_id,
       JSON_OBJECTAGG(
         JSON_VALUE(event_data, '$.action'),
         JSON_VALUE(event_data, '$.score' RETURNING UNSIGNED)
       ) AS score_by_action
FROM user_events
GROUP BY user_id;

+---------+--------------------------------+
| user_id | score_by_action                |
+---------+--------------------------------+
|       1 | {"login": 88, "purchase": 72}  |
|       2 | {"login": 91, "purchase": 84}  |
|       3 | {"logout": 65}                 |
+---------+--------------------------------+
3 rows in set (0.00 sec)

JSON_OBJECTAGG() は、グループ内に重複するキーが存在する場合にエラーをスローします。これは、本番の ETL パイプラインで遭遇する前に知っておく価値があります。その場合、上流で重複を除去するか、データがこの集計ステップに到達する前にアプリケーション logic で処理する必要があります。

JSON を多用したクエリ実行後の SHOW STATUS の確認

クエリパターンを評価する際、ハンドラーメトリクスの確認は有用な習慣です:

FLUSH STATUS;

SELECT * FROM user_events
WHERE JSON_VALUE(event_data, '$.score' RETURNING UNSIGNED) > 80;

SHOW STATUS LIKE 'Handler_read%';

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_read_first         | 1     |
| Handler_read_key           | 0     |
| Handler_read_last          | 0     |
| Handler_read_next          | 4     |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 6     |
+----------------------------+-------+
7 rows in set (0.00 sec)

Handler_read_rnd_next の値はフルスキャンを確認しています — score 値に機能的インデックスがないため驚くことではありません。スケールでの score ベースのフィルタリングには、インデックス付きの生成カラムが正しい解決策です:

ALTER TABLE user_events
  ADD COLUMN score_val TINYINT UNSIGNED
    GENERATED ALWAYS AS (JSON_VALUE(event_data, '$.score' RETURNING UNSIGNED)) VIRTUAL,
  ADD INDEX idx_score (score_val);

これを追加した後、同じクエリは適切なインデックス範囲スキャンに低下します。JSON フィールド上の生成カラムは MySQL 8.0 と Percona Server 8.0 の両方で利用可能であり、いかなる意味のあるスケールでもスカラー JSON フィールドのフィルタリングに対して最も信頼性の高い方法です。

Percona Server を使用している場合、Percona Toolkitpt-query-digest が、本番環境で実際に問題を引き起こしている JSON を多用したクエリを特定するための最も実践的な方法であり、推測的にインデックスを追加する前に使用することをお勧めします。

実践的な観察

  • マルチバリューインデックス (8.0.17+) は長らく待ち望まれた改善であり、クエリパターンが JSON_CONTAINS() または MEMBER OF() と一致する場合にうまく機能します
  • JSON_VALUE() with RETURNING (8.0.21+) は、古い抽出後のキャストパターンよりもクリーンで、一貫して採用する価値があります
  • 生成カラムとインデックスは、スケールでのスカラー JSON フィールドフィルタリングに対して最も信頼性の高い方法です
  • グループ化されたデータでの JSON_OBJECTAGG() の重複キーエラーを監視してください — ETL パイプラインでハードエラーとして表面化し、サンプルデータがたまたまクリーンであればテストで簡単に逃すことがあります
  • 常に EXPLAIN でインデックスの使用を確認してください — オプティマイザは複雑な WHERE 句でマルチバリューインデックスを常に選択するわけではなく、仮定するよりも確認する価値があります

まとめ

MySQL 8.0 の JSON 改善は本当有用であり、特にマルチバリューインデックスと型キャスト付きの JSON_VALUE() がそうです。これらは良好なスキーマ設計に代わるものではありませんが、JSON ストレージが適切または継承された場合、オプティマイザが勝手に解決してくれることを願うのではなく、本物のツールが利用可能になりました。特に、特定の JSON フィールドが WHERE 句で頻繁に使用されることがわかっている場合は、生成カラムパターンを早い段階で評価する価値があります。

有用な参考資料:

2025年7月4日金曜日

MySQL解析:AI搭載CLIツールによる

MySQL解析:AI搭載CLIツールによる

本記事は https://anothermysqldba.blogspot.com/2025/07/mysql-analysis-with-ai-powered-cli-tool.html の翻訳版です。

MySQLのDBAとして、私たちはLinuxターミナルウィンドウでの作業が多いです。また、利用可能な無料オプションを好みます。この投稿では、ターミナルウィンドウにとどまりながらAI搭載ツールを使用できるアプローチを紹介します。他の直接AIプロバイダーを使用するよう更新することもできますが、この例ではaimlapi.comを使用するよう設定しました。これは、限定的な使用では無料で、より多くのテスト用には非常に低コストで複数のAIモデルをターミナルに提供するためです。

注:私はAIMLAPIの有料スポークスマンでも何でもありません - これはアイデアを強調するための簡単な例に過ぎません。

問題

数百のテーブルを持つレガシーデータベースを見ています。それぞれに複雑な関係と、何年も前に行われた疑わしい設計決定があります。通常のプロセスには以下が含まれます:

  • 手動のスキーマ検査
  • ドキュメントの相互参照(存在する場合)
  • 複数のEXPLAINクエリの実行
  • ベストプラクティスガイドの参照
  • 同僚のセカンドオピニオンを求める

これは時間がかかり、しばしば見落としがあります。

CLIベースのアプローチ

CLIから直接AIを活用し、多くのことを行うことができます。MySQL解析の支援は、このアプローチが日常のデータベースタスクでどのように機能するかの一例に過ぎません。MySQLのネイティブ機能とAIモデルを組み合わせ、すべてシンプルなコマンドラインインターフェースを通じてアクセスできることで、ターミナルを離れることなく洞察を得ることができます。AIMLAPIは限定使用で100以上のAIモデルへの無料アクセスを提供し、このアプローチをアクセス可能にしています。より集中的なテストでも、コストは非常に合理的なままです。

ツール:AIMLAPI CLI

では、単一のインターフェースを通じて100以上のAIモデルへのアクセスを提供するbashスクリプトをご紹介します:

#!/bin/bash
# 100以上のAIモデルにアクセスできるAIMLAPI CLIツール
# ファイル: ~/.local/bin/aiml

# 設定
DEFAULT_MODEL=${AIMLAPI_DEFAULT_MODEL:-"gpt-4o"}
MAX_TOKENS=${AIMLAPI_MAX_TOKENS:-2000}
TEMPERATURE=${AIMLAPI_TEMPERATURE:-0.7}
BASE_URL="https://api.aimlapi.com"
ENDPOINT="v1/chat/completions"

# 出力用カラーコード
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # カラーなし

# カラー出力を印刷する関数
print_info() { echo -e "${BLUE}[情報]${NC} $1"; }
print_success() { echo -e "${GREEN}[成功]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[警告]${NC} $1"; }
print_error() { echo -e "${RED}[エラー]${NC} $1"; }
print_model() { echo -e "${PURPLE}[モデル]${NC} $1"; }

# 人気のモデルショートカット
declare -A MODEL_SHORTCUTS=(
    # OpenAIモデル
    ["gpt4"]="gpt-4o"
    ["gpt4o"]="gpt-4o"
    ["gpt4mini"]="gpt-4o-mini"
    ["o1"]="o1-preview"
    ["o3"]="openai/o3-2025-04-16"
    
    # Claudeモデル  
    ["claude"]="claude-3-5-sonnet-20241022"
    ["claude4"]="anthropic/claude-sonnet-4"
    ["opus"]="claude-3-opus-20240229"
    ["haiku"]="claude-3-5-haiku-20241022"
    ["sonnet"]="claude-3-5-sonnet-20241022"
    
    # DeepSeekモデル
    ["deepseek"]="deepseek-chat"
    ["deepseek-r1"]="deepseek/deepseek-r1"
    ["reasoner"]="deepseek-reasoner"
    
    # Googleモデル
    ["gemini"]="gemini-2.0-flash"
    ["gemini2"]="gemini-2.0-flash"
    ["gemini15"]="gemini-1.5-pro"
    
    # Meta Llamaモデル
    ["llama"]="meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo"
    ["llama405b"]="meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo"
    
    # Qwenモデル
    ["qwen"]="qwen-max"
    ["qwq"]="Qwen/QwQ-32B"
    
    # Grokモデル
    ["grok"]="x-ai/grok-beta"
    ["grok3"]="x-ai/grok-3-beta"
    
    # 専門モデル
    ["coder"]="Qwen/Qwen2.5-Coder-32B-Instruct"
)

# モデルショートカットを解決する関数
resolve_model() {
    local model="$1"
    if [[ -n "${MODEL_SHORTCUTS[$model]}" ]]; then
        echo "${MODEL_SHORTCUTS[$model]}"
    else
        echo "$model"
    fi
}

# 適切なエスケープのためjqを使用してJSONペイロードを作成する関数
create_json_payload() {
    local model="$1"
    local prompt="$2"
    local system_prompt="$3"
    
    local temp_file=$(mktemp)
    echo "$prompt" > "$temp_file"
    
    if [ -n "$system_prompt" ]; then
        jq -n --arg model "$model" \
              --rawfile prompt "$temp_file" \
              --arg system "$system_prompt" \
              --argjson max_tokens "$MAX_TOKENS" \
              --argjson temperature "$TEMPERATURE" \
              '{
                model: $model,
                messages: [{role: "system", content: $system}, {role: "user", content: $prompt}],
                max_tokens: $max_tokens,
                temperature: $temperature
              }'
    else
        jq -n --arg model "$model" \
              --rawfile prompt "$temp_file" \
              --argjson max_tokens "$MAX_TOKENS" \
              --argjson temperature "$TEMPERATURE" \
              '{
                model: $model,
                messages: [{role: "user", content: $prompt}],
                max_tokens: $max_tokens,
                temperature: $temperature
              }'
    fi
    
    rm -f "$temp_file"
}

# AIMLAPIを呼び出す関数
call_aimlapi() {
    local prompt="$1"
    local model="$2"
    local system_prompt="$3"
    
    if [ -z "$AIMLAPI_API_KEY" ]; then
        print_error "AIMLAPI_API_KEYが設定されていません"
        return 1
    fi
    
    model=$(resolve_model "$model")
    
    local json_file=$(mktemp)
    create_json_payload "$model" "$prompt" "$system_prompt" > "$json_file"
    
    local response_file=$(mktemp)
    local http_code=$(curl -s -w "%{http_code}" -X POST "${BASE_URL}/${ENDPOINT}" \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $AIMLAPI_API_KEY" \
        --data-binary @"$json_file" \
        -o "$response_file")
    
    if [ "$http_code" -ne 200 ] && [ "$http_code" -ne 201 ]; then
        print_error "HTTPエラー $http_code"
        cat "$response_file" >&2
        rm -f "$json_file" "$response_file"
        return 1
    fi
    
    local content=$(jq -r '.choices[0].message.content // empty' "$response_file" 2>/dev/null)
    
    if [ -z "$content" ]; then
        content=$(jq -r '.choices[0].text // .message.content // .content // empty' "$response_file" 2>/dev/null)
    fi
    
    if [ -z "$content" ]; then
        local error_msg=$(jq -r '.error.message // .error // empty' "$response_file" 2>/dev/null)
        if [ -n "$error_msg" ]; then
            echo "APIエラー: $error_msg"
        else
            echo "エラー: APIレスポンスを解析できません"
        fi
    else
        echo "$content"
    fi
    
    rm -f "$json_file" "$response_file"
}

# 引数解析を伴うメイン関数
main() {
    local model="$DEFAULT_MODEL"
    local system_prompt=""
    local prompt=""
    local piped_input=""
    
    if [ -p /dev/stdin ]; then
        piped_input=$(cat)
    fi
    
    # 引数を解析
    while [[ $# -gt 0 ]]; do
        case $1 in
            -m|--model)
                model="$2"
                shift 2
                ;;
            -s|--system)
                system_prompt="$2"
                shift 2
                ;;
            *)
                prompt="$*"
                break
                ;;
        esac
    done
    
    # 入力を処理
    if [ -n "$piped_input" ] && [ -n "$prompt" ]; then
        prompt="$prompt

分析するデータは以下です:
$piped_input"
    elif [ -n "$piped_input" ]; then
        prompt="このデータを分析してください:

$piped_input"
    elif [ -z "$prompt" ]; then
        echo "使用法: aiml [オプション] \"プロンプト\""
        echo "       コマンド | aiml [オプション]"
        exit 1
    fi
    
    local resolved_model=$(resolve_model "$model")
    print_info "$resolved_model に問い合わせ中..."
    
    local response=$(call_aimlapi "$prompt" "$model" "$system_prompt")
    
    echo ""
    print_model "$resolved_model からの応答:"
    echo "----------------------------------------"
    echo "$response" 
    echo "----------------------------------------"
}

# 依存関係をチェック
check_dependencies() {
    command -v curl >/dev/null 2>&1 || { print_error "curlが必要ですがインストールされていません。"; exit 1; }
    command -v jq >/dev/null 2>&1 || { print_error "jqが必要ですがインストールされていません。"; exit 1; }
}

check_dependencies
main "$@"

このスクリプトは、claude4gpt4grok3などのシンプルなショートカットを通じて、さまざまなAIモデルへのアクセスを提供します。AIMLAPIは、限定使用ですべてのモデルへの無料アクセスを提供し、追加テスト用の合理的なコストを提供しています。予算を破ることなく実験したいDBAに適しています。

スクリプトの機能

スクリプトには包括的なヘルプが含まれています。aiml --helpで表示される内容は以下の通りです:

AIMLAPI CLIツール - 100以上のAIモデルへのアクセス
===============================================
使用法: aiml [オプション] "プロンプト"
        コマンド | aiml [オプション]
コアオプション:
  -m, --model モデル        使用するモデル (デフォルト: gpt-4o)
  -t, --tokens 数値         最大トークン数 (デフォルト: 2000)
  -T, --temperature 浮動小数点  温度 0.0-2.0 (デフォルト: 0.7)
  -s, --system プロンプト    モデル動作用システムプロンプト
入力/出力オプション:
  -f, --file ファイル       ファイルからプロンプトを読み込む
  -o, --output ファイル     応答をファイルに保存
  -r, --raw                生出力 (フォーマット/色なし)
情報オプション:
  -l, --list               人気のモデルショートカットをリスト
  --get-models             APIから利用可能な全モデルを取得
  -c, --config             現在の設定を表示
  -v, --verbose            詳細出力を有効化
  -d, --debug              デバッグ情報を表示
  -h, --help               このヘルプを表示
基本例:
  aiml "量子コンピューティングを説明して"
  aiml -m claude "このコードをレビューして"
  aiml -m deepseek-r1 "この数学問題を段階的に解いて"
  aiml -m grok3 "AIの最新動向は何ですか?"
  aiml -m coder "このPython関数を最適化して"
パイプ例:
  ps aux | aiml "これらのプロセスを分析して"
  netstat -tuln | aiml "これらのネットワーク接続を説明して"
  cat error.log | aiml -m claude "これらのエラーを診断して"
  git diff | aiml -m coder "これらのコード変更をレビューして"
  df -h | aiml "ディスク使用量を分析してクリーンアップを提案して"
ファイル操作:
  aiml -f prompt.txt -o response.txt
  aiml -f large_dataset.csv -m llama405b "このデータを分析して"
  cat script.py | aiml -m coder -o review.md "コードレビュー"
モデルカテゴリとショートカット:
  OpenAI:     gpt4, gpt4mini, o1, o3
  Claude:     claude, opus, haiku, sonnet, claude4
  DeepSeek:   deepseek, deepseek-r1, reasoner
  Google:     gemini, gemini2, gemma
  Meta:       llama, llama3, llama4, llama405b
  Qwen:       qwen, qwen2, qwq
  Grok:       grok, grok3, grok3mini
  コーディング: coder, codestral
高度な使用法:
  aiml -m claude -s "あなたはセキュリティエキスパートです" "このコードを監査して"
  aiml -m deepseek-r1 -t 3000 "複雑な推論タスク"
  aiml -v -m grok3 "詳細ログ付きの詳細クエリ"
  aiml -d "API問題をトラブルシューティングするためのデバッグモード"
モデル発見:
  aiml -l                   # 人気のショートカットを表示
  aiml --get-models         # APIから利用可能な全モデルを取得
  aiml --config             # 現在の設定を表示
環境変数:
  AIMLAPI_API_KEY          - あなたのAIMLAPIキー (必須)
  AIMLAPI_DEFAULT_MODEL    - デフォルトモデル (オプション)
  AIMLAPI_MAX_TOKENS       - デフォルト最大トークン数 (オプション)
  AIMLAPI_TEMPERATURE      - デフォルト温度 (オプション)
プロのヒント:
  • プログラミングタスクとコードレビューには coder を使用
  • 複雑な推論と数学問題には deepseek-r1 を使用
  • 詳細分析と長文コンテンツには claude4 を使用
  • 最新イベントとリアルタイム情報には grok3 を使用
  • APIコストを節約するための簡単な質問には gpt4mini を使用
  • コマンド出力を直接パイプ: コマンド | aiml "これを分析して"
  • 使用中のモデルを確認するには -v を使用
  • 100以上の利用可能モデルを確認するには --get-models を使用

シンプルなインターフェースを通じて100以上のAIモデルへのアクセス!

例:Cityテーブル

実際のMySQLテーブル解析でこれがどのように機能するかを示します。クラシックなWorldデータベース(https://dev.mysql.com/doc/index-other.html サンプルデータベースより)のCityテーブルを3つの異なるAIモデルを使用して解析します。

コマンド

mysql --login-path=klarson world -e "show create table City\G" | \
aiml --model claude4 "MySQLエキスパートの観点からこのテーブルを分析してください"

このコマンドは:

  1. MySQLからテーブル構造を抽出
  2. AIツールにパイプで送信
  3. Claude Sonnet 4から解析を取得

結果

Claude Sonnet 4の解析

Claude 4は整理された解析を提供しました:

強み:

  • InnoDBの効率性のための適切なAUTO_INCREMENT主キー
  • 参照整合性を保つ外部キー制約
  • 一般的なクエリに適したインデックス戦略

発見された問題:

  • ストレージ非効率性: 可変長都市名にCHAR(35)を使用するとスペースが無駄になる
  • 文字セット制限: latin1文字セットは国際的な都市名には不適切
  • 最適でないインデックス: name_keyインデックスは最初の5文字のみをカバー

提案された改善:

-- Claudeの提案による最適化構造
CREATE TABLE `City` (
  `ID` int NOT NULL AUTO_INCREMENT,
  `Name` VARCHAR(35) NOT NULL,
  `CountryCode` CHAR(3) NOT NULL,
  `District` VARCHAR(20) NOT NULL,
  `Population` int UNSIGNED NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`),
  KEY `name_idx` (`Name`),
  KEY `country_name_idx` (`CountryCode`, `Name`),
  KEY `population_idx` (`Population`),
  CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) 
    REFERENCES `Country` (`Code`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4080 
  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Grok 3 Betaの解析

mysql --login-path=klarson world -e "show create table City\G" | \
aiml --model grok3 "MySQLエキスパートの観点からこのテーブルを分析してください"

Grok 3は詳細で包括的な解析を提供しました:

技術的深堀り:

  • パフォーマンス影響解析: 部分インデックス制限を詳細に評価
  • ストレージエンジンの利点: トランザクション整合性のためのInnoDB選択を確認
  • データ型最適化: 例付きの詳細なスペース節約推奨事項

高度な考慮事項:

  • 都市名検索のためのフルテキストインデックス推奨事項
  • 特定のコマンドを含む文字セット移行手順
  • 大きなデータセットのための分割戦略

実装ガイドライン:

-- Grokの文字セット移行提案
ALTER TABLE City CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- フルテキストインデックス推奨事項
ALTER TABLE City ADD FULLTEXT INDEX name_fulltext (Name);

GPT-4oの解析

mysql --login-path=klarson world -e "show create table City\G" | \
aiml --model gpt4 "MySQLエキスパートの観点からこのテーブルを分析してください"

GPT-4oは実用的で直接実行可能な改善に焦点を当てました:

実用的評価:

  • AUTO_INCREMENT主キー設計を検証
  • データ整合性のための外部キー制約の利点を確認
  • グローバルアプリケーションのための文字セット制限を特定

実装準備完了の提案:

  • 即座の最適化のための特定のALTER TABLEコマンド
  • クエリパターン解析推奨事項
  • インデックス効果評価基準

マルチモデル解析の力

このアプローチが価値あるものとなる理由は、3つの異なる視点を得ることです:

  1. Claude 4: 具体的なコードソリューションを含む詳細で構造化された解析を提供
  2. Grok 3: 高度な最適化戦略を含む包括的なカバレッジを提供
  3. GPT-4o: 実用的で直接実行可能な推奨事項を提供

各モデルは独自の強みをもたらします:

  • 異なる焦点: ストレージ最適化 vs パフォーマンス vs 保守性
  • さまざまな深度レベル: 迅速な勝利からアーキテクチャ改善まで
  • 多様な解析スタイル: 構造化 vs 包括的 vs 実用的

MySQL以外:その他のCLI例

任意のコマンド出力をAIツールにパイプできるため、他の有用な例をいくつか示します:

システム管理

# システムプロセスを分析
ps aux | aiml "どのプロセスが最もリソースを使用していますか?"

# ディスク使用量をチェック
df -h | aiml "ディスク使用量を分析してクリーンアップを提案してください"

# ネットワーク接続
netstat -tuln | aiml "これらのネットワーク接続を説明してください"

# システムログ
tail -50 /var/log/syslog | aiml "これらのログに気になるエラーはありますか?"

ファイルとディレクトリの解析

# 大きなファイル
find /var -size +100M | aiml "これらの大きなファイルをタイプ別に整理してください"

# 権限の問題
ls -la /etc/mysql/ | aiml "セキュリティのためにこれらのファイル権限をチェックしてください"

# 設定レビュー
cat /etc/mysql/my.cnf | aiml "このMySQL設定をレビューしてください"

ログ解析

# Apacheログ
tail -100 /var/log/apache2/error.log | aiml "これらのWebサーバーエラーを要約してください"

# 認証ログ
grep "Failed password" /var/log/auth.log | aiml "これらの失敗したログイン試行を分析してください"

要点は、ターミナルを離れることなく迅速な解析を得るために、ほぼ何でもパイプできることです。

ワークフローの実装

セットアップ手順

1. 依存関係のインストール:

# 必要なツールをインストール
sudo apt install curl jq mysql-client

# スクリプトディレクトリを作成
mkdir -p ~/.local/bin

# スクリプトを実行可能にする
chmod +x ~/.local/bin/aiml

2. APIアクセスの設定:

# https://aimlapi.com から無料のAIMLAPIキーを取得(限定使用の無料ティア)
export AIMLAPI_API_KEY="あなたの無料APIキーここ"
echo 'export AIMLAPI_API_KEY="あなたの無料APIキーここ"' >> ~/.bashrc

3. セットアップのテスト:

# 設定を確認
aiml --config

# 基本機能をテスト
echo "SELECT VERSION();" | aiml "このSQLを説明してください"

実用的な使用パターン

迅速なテーブル解析

# 特定のテーブルを解析
mysql -e "SHOW CREATE TABLE users\G" mydb | \
aiml -m claude4 "このMySQLテーブル構造を解析してください"

異なるモデルの視点を比較

# 同じテーブルに対する複数の視点を取得
TABLE_DDL=$(mysql -e "SHOW CREATE TABLE orders\G" ecommerce)

echo "$TABLE_DDL" | aiml -m claude4 "MySQLテーブル解析"
echo "$TABLE_DDL" | aiml -m grok3 "パフォーマンス最適化レビュー" 
echo "$TABLE_DDL" | aiml -m gpt4 "実用的改善提案"

複数テーブルの解析

# データベース内の全テーブルの迅速解析
mysql -e "SHOW TABLES;" mydb | \
while read table; do
  echo "=== $table を解析中 ==="
  mysql -e "SHOW CREATE TABLE $table\G" mydb | \
  aiml -m gpt4mini "このテーブルの迅速評価"
done

インデックス解析

# インデックス使用と最適化をレビュー
mysql -e "SHOW INDEX FROM tablename;" database | \
aiml -m deepseek "このMySQLテーブルのインデックス最適化を提案してください"

クエリパフォーマンス解析

# 遅いクエリを解析
mysql -e "SHOW PROCESSLIST;" | \
aiml -m grok3 "これらのMySQLプロセスで潜在的なパフォーマンス問題を特定してください"

なぜAIMLAPIがDBAにとってこれを可能にするのか

合理的なコストでの無料アクセス: AIMLAPIは100以上のAIモデルへの限定使用での無料アクセスを提供し、追加テスト用の非常に合理的な価格設定を行っています。これは、高価なサブスクリプションにコミットすることなく実験したいDBAに最適です。

モデルの多様性: 異なるプロバイダー(OpenAI、Anthropic、Google、Metaなど)のモデルへのアクセスは、多様な視点と専門分野を得ることを意味します。

ベンダーロックインなし: 長期的なコミットメントなしに、特定のニーズに最適なモデルを見つけるために異なるモデルで実験できます。

ターミナルネイティブ: すでにMySQLの作業を行っている快適なLinux環境にとどまります。

モデル選択ガイド

異なるモデルはMySQL解析の異なる側面で優れています:

# 詳細な構造解析のため
aiml -m claude4 "包括的なテーブル構造レビュー"

# パフォーマンス重視の解析のため  
aiml -m grok3 "パフォーマンス最適化推奨事項"

# 迅速で実用的な提案のため
aiml -m gpt4 "即座に実行可能な改善"

# トレードオフに関する複雑な推論のため
aiml -m deepseek-r1 "複雑な最適化トレードオフ解析"

# コスト効果的な迅速チェックのため
aiml -m gpt4mini "テーブルの簡単評価"

高度なテクニック

カスタムシステムプロンプト

特定のコンテキストに解析を合わせる:

# eコマース重視
aiml -m claude4 -s "あなたは高トラフィックeコマースサイトのテーブルを解析しています" \
"スケーラビリティについてこのテーブルをレビューしてください"

# セキュリティ重視
aiml -m grok3 -s "あなたはセキュリティ重視のデータベースアナリストです" \
"このテーブル構造のセキュリティ評価"

# レガシーシステム重視
aiml -m gpt4 -s "あなたはレガシーシステムを現代のMySQLに移行するのを支援しています" \
"このテーブルの現代化推奨事項"

自動レポート

# 包括的なデータベース解析レポートを生成
DB_NAME="production_db"
REPORT_FILE="analysis_$(date +%Y%m%d).md"

echo "# $DB_NAME のデータベース解析レポート" > "$REPORT_FILE"
echo "$(date) に生成" >> "$REPORT_FILE"

for table in $(mysql -Ns -e "SHOW TABLES;" "$DB_NAME"); do
  echo "" >> "$REPORT_FILE"
  echo "## テーブル: $table" >> "$REPORT_FILE"
  
  mysql -e "SHOW CREATE TABLE $table\G" "$DB_NAME" | \
  aiml -m claude4 "このMySQLテーブルの簡潔な解析を提供してください" >> "$REPORT_FILE"
done

パフォーマンス最適化ワークフロー

# 包括的なパフォーマンス解析
mysql -e "SHOW CREATE TABLE heavy_table\G" db | \
aiml -m grok3 "パフォーマンスボトルネック解析"

# インデックス提案でフォローアップ
mysql -e "SHOW INDEX FROM heavy_table;" db | \
aiml -m deepseek "インデックス最適化戦略"

# 実装計画を取得
aiml -m gpt4 "これらの最適化のためのステップバイステップ実装計画を作成してください"

このアプローチの実際の利点

速度: 時間ではなく秒でエキスパートレベルの解析を取得
複数の視点: 異なるモデルが異なる問題をキャッチ
学習ツール: 各解析でMySQL最適化について新しいことを学ぶ
コスト効果的: AIMLAPIの無料ティアと合理的な価格により、この強力な解析がアクセス可能
一貫性: 異なるテーブルとデータベース間での再現可能な解析
ドキュメント: レポートを生成し、チームと発見を共有するのが簡単

最良の結果のためのヒント

  1. 構造から始める: 包括的な解析のため常に SHOW CREATE TABLE から開始
  2. 具体的なプロンプトを使用: リクエストが具体的であるほど、解析が良くなる
  3. モデルを比較: 異なるモデルは異なる側面で優れている - 複数の視点を使用
  4. 提案を検証: 本番環境の前に常に開発環境でAI推奨事項をテスト
  5. 反復: 特定の推奨事項をより深く掘り下げるためのフォローアップ質問を使用

今日から始める

このアプローチの美しさは、そのシンプルさとコスト効果です。わずかなコマンドで、次のことができます:

  1. https://aimlapi.com から無料のAIMLAPIキーを取得(無料ティアを含む)
  2. スクリプトをインストール(5分)
  3. すぐにMySQLテーブルの解析を開始
  4. ニーズに最適なモデルを見つけるために異なるモデルで実験
  5. 通常の解析には無料ティアを使用し、集中的なテストにのみ支払い

Windowsユーザー(クイックオプション)

私はWindowsの人間ではありませんが、Windowsでこれを実行する必要がある場合、最も簡単なアプローチは:

  1. WSL2をインストール(Windows Subsystem for Linux)
  2. Ubuntuをインストール Microsoft Storeから
  3. WSL2内で上記のLinuxセットアップに従う

これにより、スクリプトが設計通りに正確に動作する適切なLinux環境が提供されます。

これはDBAの専門知識を置き換えることではありません - ターミナル環境にとどまりながらそれを強化することです。AIは迅速な解析を提供し、見逃しがちなことをキャッチし、あなたがコンテキストを提供し、最終的な決定を下します。

単一のテーブルで作業するか、数百のテーブルを持つ複雑なデータベースで作業するかに関わらず、このワークフローはニーズに合わせてスケールします。AIMLAPIが追加使用に対して合理的なコストで無料アクセスを提供するため、予算の心配なしに特定の使用ケースに最適な組み合わせを実験し、見つけることができます。


MySQLの強力な内省機能とAI解析の組み合わせは、DBAにとって実用的でコスト効果的なワークフローを作成します。次のデータベース最適化プロジェクトでこれを試してみてください - 快適なターミナル環境にとどまりながら、どのような洞察が現れるかに驚くかもしれません。

2024年2月25日日曜日

MariaDB 暗号化 (保存データ)

以下は、MariaDB 暗号化のいくつかのオプションを示す簡単な例です。 

何を暗号化するかを考慮する必要があります。データ (転送中のデータ) またはインスタンス内のデータ (保存データ) の通信。 

この投稿では、Amazon Linux 上で実行されている AWS 無料利用枠ノードを使用した保存データ オプションに焦点を当てます。2 つの異なるインスタンスでグローバル データベースを使用して、暗号化を使用した現在のテーブルの更新と、自動的に暗号化される新しいロード テーブルを示します。 


まず、インストールから始めます...このデモの場合のみ、すばやく簡単にインストールできます。 


# yum -y install mariadb105-server
# vi /etc/my.cnf.d/mariadb-server.cnf
# cat  /etc/my.cnf.d/mariadb-server.cnf | grep server_id 
server_id=100

# cat  /etc/my.cnf.d/mariadb-server.cnf | grep server_id
server_id=200
# systemctl start mariadb.service
# mysql
MariaDB [(none)]> status
--------------
mysql  Ver 15.1 Distrib 10.5.23-MariaDB, for Linux (x86_64) using  EditLine wrapper
Connection id: 3
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server: MariaDB
Server version: 10.5.23-MariaDB MariaDB Server
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: latin1
Db     characterset: latin1
Client characterset: utf8
Conn.  characterset: utf8
UNIX socket: /var/lib/mysql/mysql.sock
Uptime: 27 sec
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         100 |
+-------------+
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         200 |
+-------------+


グローバルデータベースをインスタンスserver_id 100にロードします。 


# mysql < world.sql
# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 5
Server version: 10.5.23-MariaDB MariaDB Server
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         100 |
+-------------+
1 row in set (0.000 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| world              |
+--------------------+
4 rows in set (0.000 sec)
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         200 |
+-------------+
1 row in set (0.000 sec)
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+
3 rows in set (0.000 sec)  


これで、両方のインスタンスが現在暗号化を使用していないことがわかります。 


MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         100 |
+-------------+
1 row in set (0.000 sec)
MariaDB [(none)]> SELECT NAME, ENCRYPTION_SCHEME, CURRENT_KEY_ID FROM information_schema.INNODB_TABLESPACES_ENCRYPTION ;
Empty set (0.000 sec)

MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         200 |
+-------------+
1 row in set (0.000 sec)
MariaDB [(none)]> SELECT NAME, ENCRYPTION_SCHEME, CURRENT_KEY_ID FROM information_schema.INNODB_TABLESPACES_ENCRYPTION ;
Empty set (0.000 sec)


次に、両方のシステムでランダムキーを設定し、暗号化します。


#  mkdir /etc/mysql/

#  mkdir /etc/mysql/encryption/
# (echo -n "1;" ; openssl rand -hex 32 ) | sudo tee -a  /etc/mysql/encryption/keyfile
# (echo -n "2;" ; openssl rand -hex 32 ) | sudo tee -a  /etc/mysql/encryption/keyfile
#  (echo -n "100;" ; openssl rand -hex 32 ) | sudo tee -a  /etc/mysql/encryption/keyfile

# cat /etc/mysql/encryption/keyfile
1;466139b487d5735b536a10502b0607d2b96dfa58a7f95ce4847d98ef585af8b5
2;a0f533c2e459dc64e0aeb1f0f8c9dfb496571e71001ca60fac35c8bbc6361096
100;4b4bfd61af39d57e068385cf1a023bdfc5972ed414a24167067ca5256fc314e6

# cat /etc/mysql/encryption/keyfile
1;f8b1b250d3bf7159e2abd15be146367415a80d3781bbcf7d96b26640d7efdc8a
2;c7eaccedd0ef561f0c08d461abfd651947230b08c71aec67c6064bbedb6408ec
100;90475521b6eb6be3c1ec02770f3e8f80b34130f37d25c89b51cf10ec6a7c5bb6

openssl rand -hex 128 > /etc/mysql/encryption/keyfile.key
openssl enc -aes-256-cbc -md sha1    -pass file:/etc/mysql/encryption/keyfile.key    -in /etc/mysql/encryption/keyfile    -out /etc/mysql/encryption/keyfile.enc

 ls -ltr /etc/mysql/encryption/
total 12
-rw-r--r--. 1 root root 203 Feb 24 23:39 keyfile
-rw-r--r--. 1 root root 257 Feb 24 23:40 keyfile.key
-rw-r--r--. 1 root root 224 Feb 24 23:41 keyfile.enc


これで、プラグインと暗号化のオプションを有効にするために cnf ファイルを設定できるようになりました。


# vi /etc/my.cnf.d/mariadb-server.cnf
[mariadb]
## File Key Management
plugin_load_add = file_key_management
loose_file_key_management_filename = /etc/mysql/encryption/keyfile
loose_file_key_management_filename = /etc/mysql/encryption/keyfile.enc
loose_file_key_management_filekey = FILE:/etc/mysql/encryption/keyfile.key
loose_file_key_management_encryption_algorithm = AES_CBC

## InnoDB/XtraDB Encryption Setup
innodb_encrypt_log = ON
innodb_encrypt_temporary_tables=ON
innodb_encryption_threads=4
innodb_encrypt_tables=ON
innodb_default_encryption_key_id=1

## Aria Encryption Setup
aria_encrypt_tables = ON

## Temp & Log Encryption
encrypt-tmp-disk-tables = 1
encrypt-tmp-files = 1
encrypt_binlog = ON



MariaDB を再起動して、現在のステータスを確認します. 
 

systemctl restart mariadb.service
mysql
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         100 |
+-------------+
1 row in set (0.001 sec)

MariaDB [(none)]> SELECT NAME, ENCRYPTION_SCHEME, CURRENT_KEY_ID FROM information_schema.INNODB_TABLESPACES_ENCRYPTION ;
+----------------------------+-------------------+----------------+
| NAME                       | ENCRYPTION_SCHEME | CURRENT_KEY_ID |
+----------------------------+-------------------+----------------+
| innodb_system              |                 1 |              1 |
| mysql/innodb_table_stats   |                 1 |              1 |
| mysql/innodb_index_stats   |                 1 |              1 |
| mysql/transaction_registry |                 1 |              1 |
| mysql/gtid_slave_pos       |                 1 |              1 |
| world/city                 |                 1 |              1 |
| world/country              |                 1 |              1 |
| world/countrylanguage      |                 1 |              1 |
+----------------------------+-------------------+----------------+
8 rows in set (0.000 sec)

MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         200 |
+-------------+
1 row in set (0.000 sec)

MariaDB [(none)]> SELECT NAME, ENCRYPTION_SCHEME, CURRENT_KEY_ID FROM information_schema.INNODB_TABLESPACES_ENCRYPTION ;
+----------------------------+-------------------+----------------+
| NAME                       | ENCRYPTION_SCHEME | CURRENT_KEY_ID |
+----------------------------+-------------------+----------------+
| innodb_system              |                 1 |              1 |
| mysql/innodb_index_stats   |                 1 |              1 |
| mysql/gtid_slave_pos       |                 1 |              1 |
| mysql/innodb_table_stats   |                 1 |              1 |
| mysql/transaction_registry |                 1 |              1 |
+----------------------------+-------------------+----------------+
5 rows in set (0.000 sec)


また、ワールドデータをインスタンスserver_id 200にアップロードします。 


# mysql < world.sql
# mysql 
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         200 |
+-------------+
1 row in set (0.000 sec)
MariaDB [(none)]> SELECT NAME, ENCRYPTION_SCHEME, CURRENT_KEY_ID FROM information_schema.INNODB_TABLESPACES_ENCRYPTION ;
+----------------------------+-------------------+----------------+
| NAME                       | ENCRYPTION_SCHEME | CURRENT_KEY_ID |
+----------------------------+-------------------+----------------+
| innodb_system              |                 1 |              1 |
| mysql/innodb_index_stats   |                 1 |              1 |
| mysql/gtid_slave_pos       |                 1 |              1 |
| mysql/innodb_table_stats   |                 1 |              1 |
| mysql/transaction_registry |                 1 |              1 |
| world/city                 |                 1 |              1 |
| world/country              |                 1 |              1 |
| world/countrylanguage      |                 1 |              1 |
+----------------------------+-------------------+----------------+
8 rows in set (0.000 sec)


information_schema.INNODB_TABLESPACES_ENCRYPTION によると、現在は暗号化されています。ただし、スキーマ レベルでは表示されません。INNODB_TABLESPACES_ENCRYPTION テーブルにある場合は暗号化されていると言われていますが  、私はテーブルとスキーマでそれを確認して確認することを好みます。


MariaDB [(none)]> show create table world.city\G
*************************** 1. row ***************************
       Table: city
Create Table: CREATE TABLE `city` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT 0,
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`),
  CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `country` (`Code`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
1 row in set (0.001 sec)


INNODB_TABLESPACES_ CIFRADO スキーマ で考慮されていることがわかります 。

したがって...テーブルにいくつかの変更を加えると役に立ちます... 


MariaDB [world]> ALTER TABLE city ENCRYPTED=Yes  ENCRYPTION_KEY_ID=1;
Query OK, 0 rows affected (0.074 sec)
Records: 0  Duplicates: 0  Warnings: 0
MariaDB [world]> ALTER TABLE country ENCRYPTED=Yes  ENCRYPTION_KEY_ID=1;
Query OK, 0 rows affected (0.031 sec)
Records: 0  Duplicates: 0  Warnings: 0
MariaDB [world]> ALTER TABLE countrylanguage  ENCRYPTED=Yes  ENCRYPTION_KEY_ID=1;
Query OK, 0 rows affected (0.033 sec)
Records: 0  Duplicates: 0  Warnings: 0

MariaDB [world]> show create table city\G
*************************** 1. row ***************************
       Table: city
Create Table: CREATE TABLE `city` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT 0,
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`),
  CONSTRAINT `city_ibfk_1` FOREIGN KEY (`CountryCode`) REFERENCES `country` (`Code`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `ENCRYPTED`=Yes `ENCRYPTION_KEY_ID`=1
1 row in set (0.000 sec)


これは簡単などです。ここまでは...次に、binlog を有効にしてさらに確認する必要があります。 

vi /etc/my.cnf.d/mariadb-server.cnf
log_bin=demo

cat /etc/my.cnf.d/mariadb-server.cnf | grep log_bin
log_bin=demo

# systemctl restart mariadb.service

MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         100 |
+-------------+
1 row in set (0.000 sec)

MariaDB [(none)]> show master status\G
*************************** 1. row ***************************
            File: demo.000001
        Position: 363
    Binlog_Do_DB:
Binlog_Ignore_DB:

MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|         200 |
+-------------+
1 row in set (0.000 sec)

MariaDB [(none)]> show master status\G
*************************** 1. row ***************************
            File: demo.000001
        Position: 363
    Binlog_Do_DB:
Binlog_Ignore_DB:
1 row in set (0.000 sec)


バイナリログを調べて確認しています... 


mariadb-binlog--base64-output=DECODE-ROWS --verbose  demo.000001

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;

/*!40019 SET @@session.max_insert_delayed_threads=0*/;

/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;

DELIMITER /*!*/;

# at 4

#240225  0:06:06 server id 100  end_log_pos 256 CRC32 0x04ce3741  Start: binlog v 4, server v 10.5.23-MariaDB-log created 240225  0:06:06 at startup

# Warning: this binlog is either in use or was not closed properly.

ROLLBACK/*!*/;

# at 256

# Encryption scheme: 1, key_version: 1, nonce: eb7991b210f3f4d2f7f21537

# The rest of the binlog is encrypted!

ERROR: Error in Log_event::read_log_event(): 'Event decryption failure', data_len: 2400465656, event_type: 240

DELIMITER ;

# End of log file

ROLLBACK /* added by mysqlbinlog */;

/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;

/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;


現在暗号化されていると表示されるのは良いことです。 


MariaDB [world]> create table city2 like city;
Query OK, 0 rows affected (0.013 sec)

MariaDB [world]> insert into city2 select * from city;
Query OK, 4079 rows affected (0.078 sec)
Records: 4079  Duplicates: 0  Warnings: 0

MariaDB [world]> show create table city2\G
*************************** 1. row ***************************
       Table: city2
Create Table: CREATE TABLE `city2` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(35) NOT NULL DEFAULT '',
  `CountryCode` char(3) NOT NULL DEFAULT '',
  `District` char(20) NOT NULL DEFAULT '',
  `Population` int(11) NOT NULL DEFAULT 0,
  PRIMARY KEY (`ID`),
  KEY `CountryCode` (`CountryCode`)
) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci `ENCRYPTED`=Yes `ENCRYPTION_KEY_ID`=1
1 row in set (0.000 sec)


¿Tienes binlog? mariadb_binlog es --read-from-remote-server とともに使用すると、ログ内のデータを確認できます.

mariadb-binlog  --base64-output=DECODE-ROWS --verbose --read-from-remote-server   demo.000001 | more
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#240225  0:06:06 server id 100  end_log_pos 256 CRC32 0x04ce3741  Start: binlog v 4, server v 10.5.23-MariaDB-log created 240225  0:06:06 at startup
ROLLBACK/*!*/;
# at 256
#240225  0:06:06 server id 100  end_log_pos 296 CRC32 0x0c89f3bb  Ignorable
# Ignorable event type 164 (Start_encryption)
# at 296
#240225  0:06:06 server id 100  end_log_pos 325 CRC32 0x535776a2  Gtid list []
# at 325
#240225  0:06:06 server id 100  end_log_pos 363 CRC32 0x2ac4a61b  Binlog checkpoint demo.000001
# at 363
#240225  0:09:40 server id 100  end_log_pos 405 CRC32 0x93e10dc4  GTID 0-100-1 ddl
/*!100101 SET @@session.skip_parallel_replication=0*//*!*/;
/*!100001 SET @@session.gtid_domain_id=0*//*!*/;
/*!100001 SET @@session.server_id=100*//*!*/;
/*!100001 SET @@session.gtid_seq_no=1*//*!*/;
# at 405
#240225  0:09:40 server id 100  end_log_pos 501 CRC32 0x39269040  Query thread_id=5 exec_time=0 error_code=0
use `world`/*!*/;
SET TIMESTAMP=1708819780/*!*/;
SET @@session.pseudo_thread_id=5/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0, @@session.explicit_defaults_
for_timestamp=0/*!*/;
SET @@session.sql_mode=1411383296/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=utf8,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create table city2 like city
/*!*/;
# at 501
#240225  0:09:49 server id 100  end_log_pos 543 CRC32 0xde82b753  GTID 0-100-2 trans
/*!100001 SET @@session.gtid_seq_no=2*//*!*/;
START TRANSACTION
/*!*/;
# at 543
# at 602
#240225  0:09:49 server id 100  end_log_pos 602 CRC32 0x05bbb9e6  Annotate_rows:
#Q> insert into city2 select * from city
#240225  0:09:49 server id 100  end_log_pos 661 CRC32 0x9e0b4e0d  Table_map: `world`.`city2` mapped to number 21
# at 661


これで少なくとも始めるきっかけになれば幸いです... 


リソース

https://mariadb.com/kb/en/securing-mariadb-encryption/  

2020年11月12日木曜日

FRMファイルを使用してスキーマを確認し、idbファイルを完了します。

これは、全体的にあなたがする必要のないトピックです...なぜですか?バックアップを正しく作成したので...バックアップが機能することをテストして知っているので、それらのバックアップを復元して、つできます。 

インスタンス、角のインスタンスにあるインスタンス1インスタンスを..インスタンスインスタンスインスタンスカ登録はありませんインスタンスを..インスタンスインスタンスを設定...インスタンスだけで、インスタンスをインスタンスにする 

すべてができます。  

MySQLは前前にMySQL別をするし、これはMySQLシェルにできました。  

mysqlfrmは、このスキーマをコメントでFRMファイルからスキーマを入力します。 

mysqlfrm --diagnostic city.frm
# WARNING: Cannot generate character set or collation names without the --server option. # CAUTION: The diagnostic mode is a best-effort parse of the .frm file. As such, it may not identify all of the components of the table correctly. This is especially true for damaged files. It will also not read the default values for the columns and the resulting statement may not be syntactically correct.
# Reading .frm file for city.frm:
# The .frm file is a TABLE.
# CREATE TABLE Statement:

CREATE TABLE `city` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Name` char(160) DEFAULT NULL,
  `CountryCode` char(12) NOT NULL,
  `District` char(80) NOT NULL,
  `Population` int(11) NOT NULL,
PRIMARY KEY `PRIMARY` (`ID`),
KEY `CountryCode` (`CountryCode`),
KEY `popkey` (`Population`)
) ENGINE=InnoDB;

#...done.


失ったスキーマができたので... DB衣表を再着します。例話、世界DBから都市データを失ったとデータます。 

$ cp  city.ibd  / tmp /  

$ cp city.ibd /tmp/
mysql> LOCK TABLES city WRITE;
mysql> ALTER TABLE city DISCARD TABLESPACE;

cp city.ibd /edb/local/mysql/data/rundeck/
chown tmdba:dba /edb/local/mysql/data/rundeck/city.ibd

mysql> ALTER TABLE city IMPORT TABLESPACE;
mysql> UNLOCK TABLES;
mysql> SELECT COUNT(*) FROM city;


2020年9月22日火曜日

MySQL mysql_config_editor&expect

 これは、自動化ツールでmysql_config_editorコマンドを使用する可能性がある人を助けるためのメモです。 

mysql_config_editorはパスワード引数を取らないため、mysql_config_editorを使用しようとする.my.cnfファイルにパスワードを設定する前に自動化ツールが失敗する可能性があります。 

expectツールを使用しても、それは可能で非常に簡単です。 

 yum -y install expect  

apt-getでも機能します。 


したがって、この例では、単純なbashスクリプトバージョンを示します。 

1つ目は、ログインパスが機能しない... 

mysql --login-path=local

ERROR 1045 (28000): Access denied for user


これを期待して設定します 

これは、bashスクリプトを介して実行します。  

expect <<EOD

spawn mysql_config_editor set --login-path=local --host=localhost --user=root --password 

expect "password"

send  -- "<PASSWORD>\r"

interact

EOD


今ではうまくいきます...

mysql --login-path=local

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 1002

2020年3月16日月曜日

MySQL&Dockers ...簡単なセットアップ

MySQL&Dockers ...は新しい概念ではなく、人々はしばらくの間Dockersに移行しています。 開発のためにこれに移行しようとしている人にとっては、いくつかのハードルがあります。

MySQLはローカルで正常に動作しますが、MySQLの異なるバージョン間でコードをテストする場合は、いくつかのバージョンを簡単に入手できると便利です。

長年の選択肢の1つは、もちろんGiuseppe Maxiaによるhttps://mysqlsandbox.net/です。 これは、複数のインスタンスを起動し、レプリケーションなどをテストできる非常に有効なソリューションです。

ドッカーは、MySQLのさまざまなバージョンでのテストに関して、よく使用される別のシナリオにもなりました。 以下は、いくつかのバージョンを簡単にインストールするためのいくつかのステップについて説明します。 私はOSXを使用しているため、これらの例はOSX用です。

起動するにはDockerが必要です。もちろんDocker Desktopは、簡単にアクセスできる便利なツールです。

Dockerをセットアップしたら、MySQLの環境を整えることができます。

ここでは、MySQLデータディレクトリ、構成ファイル、および必要に応じてmysql-filesディレクトリを含むDockerフォルダーを作成しました。

mkdir ~/Docker ;

mkdir ~/Docker/mysql_data;
mkdir ~/Docker/mysql-files;
mkdir ~/Docker/cnf;

今mysql_data内


cd ~/Docker/mysql_data;
mkdir 8.0;
mkdir 5.7;
mkdir 5.6;
mkdir 5.5;


次に、この例の簡単なcnfファイルを設定します。 主な注意事項は、バインドアドレスです。 これは、Dockerの外部でMySQLにアクセスできるようにするために設定されています。 また、これらのファイルを使用して、MySQL Dockerインスタンスごとに適切な追加の構成情報を設定できることにも気付くことができます。



cd ~/Docker/cnf;

cat my.8.0.cnf
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= /var/lib/mysql-files
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
bind-address = 0.0.0.0
port=3306
server-id=80


# Custom config should go here
!includedir /etc/mysql/conf.d/

cat my.5.7.cnf
[mysqld]
bind-address = 0.0.0.0
server-id=57
max_allowed_packet=32M

$ cat my.5.6.cnf
[mysqld]
bind-address = 0.0.0.0
server-id=56

$ cat my.5.5.cnf
[mysqld]
bind-address = 0.0.0.0
server-id=55


設定ファイルがセットアップされたので、ドッカーを構築する必要があります。 ビルドコマンドに関して注意すべきいくつかの点。

--nameドッカーの名前付き参照を設定します。

ここでは、構成ファイル、データディレクトリ、およびmysql-filesディレクトリをdockerにマッピングしています。 これにより、my.cnfファイルなどを簡単に調整できます。
-v〜/ Docker / cnf / my.8.0.cnf:/etc/mysql/my.cnf
-v〜/ Docker / mysql_data / 8.0:/ var / lib / mysql
-v〜/ Docker / mysql-files:/ var / lib / mysql-files

Dockerの外部でこれらのMySQLインスタンスに到達できるようにしたいので、それに応じてポートを公開およびマップする必要があります。
-p 3306:3306これは、ドッカー内の3306に対して3306ローカル
-p 3307:3306これは、ドッカー内の3306に対してローカルな3307を意味します。
-p 3308:3306これは、ドッカー内の3306にローカルな3308を意味します。
-p 3309:3306これは、3309がdocker内部の3306に対してローカルであることを意味します。

次に、いくつかの環境変数も渡します。
-e MYSQL_ROOT_HOST =%-e MYSQL_ROOT_PASSWORD = <ここにパスワードを設定>

まとめて...


docker run --restart always --name mysql8.0 -v ~/Docker/cnf/my.8.0.cnf:/etc/mysql/my.cnf -v ~/Docker/mysql_data/8.0:/var/lib/mysql -v ~/Docker/mysql-files:/var/lib/mysql-files -p 3306:3306 -d -e MYSQL_ROOT_HOST=% -e MYSQL_ROOT_PASSWORD=<set a password here> mysql:8.0

docker run --restart always --name mysql5.7 -v ~/Docker/cnf/my.5.7.cnf:/etc/mysql/my.cnf -v ~/Docker/mysql_data/5.7:/var/lib/mysql -v ~/Docker/mysql-files:/var/lib/mysql-files -p 3307:3306 -d -e MYSQL_ROOT_HOST=% -e MYSQL_ROOT_PASSWORD=<set a password here> mysql:5.7

docker run --restart always --name mysql5.6 -v ~/Docker/cnf/my.5.6.cnf:/etc/mysql/my.cnf -v ~/Docker/mysql_data/5.6:/var/lib/mysql -v ~/Docker/mysql-files:/var/lib/mysql-files -p 3308:3306 -d -e MYSQL_ROOT_HOST=% -e MYSQL_ROOT_PASSWORD=<set a password here> mysql:5.6

docker run --restart always --name mysql5.5 -v ~/Docker/cnf/my.5.5.cnf:/etc/mysql/my.cnf -v ~/Docker/mysql_data/5.5:/var/lib/mysql -v ~/Docker/mysql-files:/var/lib/mysql-files -p 3309:3306 -d -e MYSQL_ROOT_HOST=% -e MYSQL_ROOT_PASSWORD=<set a password here> mysql:5.5

上記のコマンドを実行するたびに、IDが返されます。
例:3cb07d7c21476fbf298648986208f3429ec664167d8eef7fed17bf9ee3ce6316

Docker Desktopを使用して各Dockerターミナルを簡単に起動/再起動してアクセスするか、関連するIDをメモしてターミナルから実行できます。

Docker Desktopには、渡したすべての変数も表示されるため、検証できます。
もちろん、ここからCLIにアクセスして、簡単に停止および開始または破棄することもできます。


$ docker exec -it 3cb07d7c21476fbf298648986208f3429ec664167d8eef7fed17bf9ee3ce6316 /bin/sh; exit
# mysql -p

Dockerコンテナーが既に実行されている場合は、ローカルホスト端末経由でMySQLにアクセスできます。

$ mysql --host=localhost --protocol=tcp --port=3306 -p -u root

アクセスの問題がある場合は、MySQLアカウントが正しいこと、ポートとマッピングが正しいことを確認してください。
  • 「初期通信パケットの読み取り」でMySQLサーバーへの接続が失われました
  • エラー1045(28000):ユーザー 'root'@'192.168.0.5'のアクセスが拒否されました(パスワードを使用:YES)

これで、すべてが稼働しており、サーバーIDがcnfファイル初期化機能ごとに設定したものと一致していることがわかります。

$ mysql --host=localhost --protocol=tcp --port=3306 -e "Select @@hostname, @@version, @@server_id "
+--------------+-----------+-------------+
| @@hostname | @@version | @@server_id |
+--------------+-----------+-------------+
| 58e9663afe8d | 8.0.19 | 80 |
+--------------+-----------+-------------+
$ mysql --host=localhost --protocol=tcp --port=3307 -e "Select @@hostname, @@version, @@server_id "
+--------------+-----------+-------------+
| @@hostname | @@version | @@server_id |
+--------------+-----------+-------------+
| b240917f051a | 5.7.29 | 57 |
+--------------+-----------+-------------+
$ mysql --host=localhost --protocol=tcp --port=3308 -e "Select @@hostname, @@version, @@server_id "
+--------------+-----------+-------------+
| @@hostname | @@version | @@server_id |
+--------------+-----------+-------------+
| b4653850cfe9 | 5.6.47 | 56 |
+--------------+-----------+-------------+
$ mysql --host=localhost --protocol=tcp --port=3309 -e "Select @@hostname, @@version, @@server_id "
+--------------+-----------+-------------+
| @@hostname | @@version | @@server_id |
+--------------+-----------+-------------+
| 22e169004583 | 5.5.62 | 55 |
+--------------+-----------+-------------+