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 |
+--------------+-----------+-------------+


2019年7月13日土曜日

MySQLどのようにテーブルスペースを復元しますか

MySQLどのようにテーブルスペースを復元しますか?

これは新しい情報ではありませんが、あまり取り上げていませんので、必要な人のためにここで取り上げます。

ibdファイルを紛失すると、データが失われます。 ですから、利用可能なもののコピーがある場合、または他のデータベースから同期している場合でも、それをインポートできます。 どのように/どのようにあなたはテーブルスペースを失いますか?

これはテーブルスペースを回復する簡単な例です。



mysql> Create database demo;

mysql> use demo;

mysql> CREATE TABLE `demotable` (
-> `id` int(11) NOT NULL AUTO_INCREMENT,
-> `dts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB;


今、私たちはいくつかのデータを保存します...


mysql> INSERT INTO demotable (id) VALUES (NULL);
Query OK, 1 row affected (0.10 sec)

mysql> INSERT INTO demotable (id) VALUES (NULL);
Query OK, 1 row affected (0.08 sec)

mysql> SELECT * FROM demotable;
+----+---------------------+
| id | dts |
+----+---------------------+
| 1 | 2019-07-12 23:31:34 |
| 2 | 2019-07-12 23:31:35 |
+----+---------------------+
2 rows in set (0.00 sec)


[OK]を今すぐそれを破ることができます..


# systemctl stop mysqld
# cd /var/lib/mysql/demo/
# ls -ltr
total 80
-rw-r-----. 1 mysql mysql 114688 Jul 12 23:31 demotable.ibd
# mv demotable.ibd /tmp/

# systemctl start mysqld
# mysql demo

mysql> show tables;
+----------------+
| Tables_in_demo |
+----------------+
| demotable |
+----------------+
1 row in set (0.00 sec)

mysql> desc demotable;
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| dts | timestamp | NO | | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------------------------+
2 rows in set (0.01 sec)

mysql> INSERT INTO demotable (id) VALUES (NULL);
ERROR 1812 (HY000): Tablespace is missing for table `demo`.`demotable`.


壊れて失われた表領域...これで回復できます。


demo]# cp /tmp/demotable.ibd .

mysql> ALTER TABLE demotable DISCARD TABLESPACE;

demo]# cp /tmp/demotable.ibd .
demo]# ls -ltr
total 112
-rw-r-----. 1 root root 114688 Jul 12 23:50 demotable.ibd
demo]# chown mysql:mysql demotable.ibd
demo]# mysql demo
mysql> ALTER TABLE demotable IMPORT TABLESPACE;
ERROR 1034 (HY000): Incorrect key file for table 'demotable'; try to repair it

mysql> REPAIR TABLE demotable;
+----------------+--------+----------+---------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+----------------+--------+----------+---------------------------------------------------------+
| demo.demotable | repair | note | The storage engine for the table doesn't support repair |
+----------------+--------+----------+---------------------------------------------------------+


今、私たちはまた別のエラーを得ました..これは通常tmpdirに利用可能なスペースに結び付けられていて、修復はとにかく.ibdのためにうまくいきません。


mysql> select @@tmpdir;
+----------+
| @@tmpdir |
+----------+
| /tmp |
+----------+

# vi /etc/my.cnf
tmpdir=/var/lib/mysql-files/

# systemctl restart mysqld
# mysql demo


たとえば、mysql-filesディレクトリを使用しました。
今すぐもう一度試すことができます。


mysql> ALTER TABLE demotable IMPORT TABLESPACE;
Query OK, 0 rows affected, 1 warning (0.61 sec)

mysql> INSERT INTO demotable (id) VALUES (NULL);
Query OK, 1 row affected (0.11 sec)

mysql> SELECT * FROM demotable;
+----+---------------------+
| id | dts |
+----+---------------------+
| 1 | 2019-07-12 23:31:34 |
| 2 | 2019-07-12 23:31:35 |
| 3 | 2019-07-12 23:56:08 |
+----+---------------------+


うまくいきました。
テーブルが1つしかない場合は、これですべて簡単で簡単です。 しかし、100年代はどうでしょうか。

それを自動化し、もちろん、あなたのinformation_schemaを使って助けてください。

テスト用にさらにコピーをいくつか作成します。

mysql> create table demotable1 like demotable;
Query OK, 0 rows affected (0.51 sec)

mysql> create table demotable2 like demotable;
Query OK, 0 rows affected (1.04 sec)

mysql> create table demotable3 like demotable;
Query OK, 0 rows affected (0.74 sec)

mysql> create table demotable4 like demotable;
Query OK, 0 rows affected (2.21 sec)


それらをすべて壊してください。

demo]# mv *.ibd /tmp/


これで、information_schema.tablesテーブルを使って、必要なすべてのコマンドを作成できます。

# vi build_discard.sql
# cat build_discard.sql
SELECT CONCAT(" ALTER TABLE ",TABLE_SCHEMA,".",TABLE_NAME," DISCARD TABLESPACE; ") as CMD FROM information_schema.TABLES WHERE TABLE_SCHEMA='demo';

# vi build_import.sql
# cat build_import.sql
SELECT CONCAT(" ALTER TABLE ",TABLE_SCHEMA,".",TABLE_NAME," IMPORT TABLESPACE; ") as CMD FROM information_schema.TABLES WHERE TABLE_SCHEMA='demo';



# mysql -N < build_import.sql > import_tablespace.sql
# mysql -N < build_discard.sql | mysql demo

demo]# cp /tmp/*.ibd .
demo]# chown mysql:mysql *.ibd
# systemctl restart mysqld
# mysql demo < import_tablespace.sql
# mysql demo

mysql> INSERT INTO demotable (id) VALUES (NULL);
Query OK, 1 row affected (0.08 sec)

mysql> INSERT INTO demotable1 (id) VALUES (NULL);
Query OK, 1 row affected (0.05 sec)

mysql> INSERT INTO demotable2 (id) VALUES (NULL);
Query OK, 1 row affected (0.09 sec)

mysql> INSERT INTO demotable3 (id) VALUES (NULL);
^[[AQuery OK, 1 row affected (0.37 sec)

mysql> INSERT INTO demotable4 (id) VALUES (NULL);
Query OK, 1 row affected (0.12 sec)



そしてそれはうまくいった。

MySQL Binlogs ::回復するには

だから私は最近出てきたこのような状況の後、私はこれについての投稿をしていないことに気づいた。

シナリオは次のとおりです。バックアップは真夜中に行われ、データベースごとにMySQLダンプを使用しました。 それから翌日の午前10時にデータベースがクラッシュしました。 電話をかける前に一連のイベントが発生しましたが、MyISAMテーブルとIBDファイルがテーブルスペースにないデータベースのバージョンに到達しました。

そのため、オプション1、バックアップから復元すると深夜になり、何時間ものデータを失うことになります。 オプション2、私たちは何千ものibdファイルを再インポートしてすべてを保存します。 それから、オプション3、バックアップからの復元、そして最近の変更にbinlogを適用しました。

それをもっと面白くするために、彼らは私が言われたibdファイルの全てを持っていませんでした、そして私はいくらかの欠けているのを見ました。 それでそれがどのように可能であったかについてよくわからないが、選択肢2は無効な選択肢になった。 彼らは、もちろん、可能な限り少ないデータ損失を望んでいたので、私たちはオプション3を使いました。

これを安全に行うために、ポート3307でMySQLの別のインスタンスを起動しました。これにより、トラフィックがポート3306インスタンスのMyISAMデータへの読み取りアクセスを行っている間も、安全に作業できます。

すべてのバックアップダンプファイルを圧縮解除して3307インスタンスにインポートすると、binlogファイルに集中することができました。

最初は、この概念は実際よりもはるかに危険に思えます。 それは実際にはかなり単純明快です。

だから最初にあなたはあなたの後のデータを見つけなければなりません。 binlogファイルを見直すことで、どのファイルが関連しているのかをすぐに知ることができます。 私の場合、どういうわけか彼らはbinlogをリセットすることができたので117ファイルはその中に2つの日付範囲を持っていました。

最初にbinlogを確認するために、次のコマンドはデータを人間が読める形式で出力します。
mysqlbinlog --defaults-file=/root/.my.cnf --base64-output=DECODE-ROWS --verbose mysql-bin.000117 > review_mysql-bin.000117.sql

*注意...上記のコマンドを実行するときは注意してください。 binlogと同じ場所に直接ファイルをダンプしていることに注意してください。 ファイル名が有効であることを確認してください。 このmysql-bin.000117.sqlは、このmysql-bin.000117 .sqlとは異なります。 あなたは2番目のオプションと.sqlの前のスペースであなたのbinlogを失うでしょう。

適用できるようにデータを保存します。 私はいくつかのbinlogを持っていたので、私はファイルを作成し、とにかく時間範囲を再確認したいと思いました。


mysqlbinlog --defaults-file=/root/.my.cnf --start-datetime="2019-07-09 00:00:00" --stop-datetime="2019-07-10 00:00:00" mysql-bin.000117 > binlog_restore.sql
mysqlbinlog --defaults-file=/root/.my.cnf mysql-bin.000118 >> binlog_restore.sql
mysqlbinlog --defaults-file=/root/.my.cnf mysql-bin.000119 >> binlog_restore.sql
mysqlbinlog --defaults-file=/root/.my.cnf --start-datetime="2019-07-10 00:00:00" --stop-datetime="2019-07-10 10:00:00" mysql-bin.000117 >> binlog_restore.sql
mysqlbinlog --defaults-file=/root/.my.cnf --stop-datetime="2019-07-10 10:00:00" mysql-bin.000120 >> binlog_restore.sql
mysqlbinlog --defaults-file=/root/.my.cnf --stop-datetime="2019-07-10 10:00:00" mysql-bin.000121 >> binlog_restore.sql

mysql --socket=/var/lib/mysql_restore/mysql.sock -e "source /var/lib/mysql/binlog_restore.sql"

今、私は与えられた時間範囲についてそれらのbinlogからのすべてのデータを適用しました。 クライアントはすべてのデータをダブルチェックし、すべて元に戻すことができてとても嬉しかったです。

この状況にはいくつかの異なる選択肢がありましたが、これはたまたまクライアントと一緒にトレーニングすることでした。

検証されたすべてが復元されたバージョンで大丈夫だったとすれば、両方のデータベースを停止し、データディレクトリを移動し(datadirのデフォルトをそのままにしておきたい)、ディレクトリを安全にしてMySQLを起動します。 復元されたインスタンスはポート3306で起動しました。