mysql explain で出てくるSelect tables optimized awayって何ですか?
日次で開発環境で実行されたクエリにEXPLAINをかけて、危なそうなクエリを通知するようにしています。 そこでこんなんが出てきました
mysql> EXPLAIN PARTITIONS SELECT MAX(`hoge_col`) AS total_count FROM `hoge_table`;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------------------------+
index貼られてないー><
↓
index貼る
↓
mysql> EXPLAIN PARTITIONS SELECT MAX(`hoge_col`) AS total_count FROM `hoge_table`;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+------------------------------+
変わらず・・・
そこでよくよく確認すると、hoge_colはprimary_keyになっていました。
で、今度は「Select tables optimized away」はなんだと。
ドキュメントを確認すると、
MySQL :: MySQL 5.6 リファレンスマニュアル :: 8.8.2 EXPLAIN 出力フォーマット
Select tables optimized away
クエリーにはすべてインデックスを使用して解決された集約関数 (MIN()、MAX())、または COUNT(*) のみが含まれていますが、GROUP BY 句は含まれていませんでした。オプティマイザは 1 行のみを返すべきであると判断しました。
オプティマイザが良きにはからってくれた結果だそうです。 内部的にはインデックスを使っているようなので、負荷等は問題なさそうです。ほぼ最速の模様。
感謝致します。
1分でできる!mysqlslapでDBのかんたん性能調査、ベンチマーク
業務中にそこそこ大きなスキーマ変更をすることになり、実際パフォーマンスに変化があるかベンチマークを取る必要が出てきました。
jmeterとかでごりょごりょとかしないとなのかーとか思ったのですが、 今回はスキーマ変更のみなので、単純にDBのみの測定でよいので、なんかいいツールはないかと探したところ、
mysqlslapなるものがあるようなので試してみました
MySQL :: MySQL 5.7 Reference Manual :: 4.5.7 mysqlslap — Load Emulation Client
MySQLクライアント負荷エミュレーション mysqlslap を使う - Qiita
mysqlslapはMySQLサーバのクライアント負荷をエミュレートし、各ステージのタイミングを報告する診断プログラムです。サーバにたいして複数のクライアントがアクセスしているかのように作動します。mysqlslapはMySQL 5.1.4.から提供されています。
さっそく試してみーる
使い方
mysqlがインストールされていれば標準でmysqlslapもインストールされているはずなので、すぐ使えます
基本的には、測定する際特定のスキーマを作って、テキトーなクエリを実行してベンチマークを取る感じのようですが、 今回は実際の本番相当のデータ量のテーブルを用意し、それに対して測定を行いました。
#測定するSQL SELECT * FROM TMP_TABLE WHERE hoge = 'hoge'
/usr/local/mysql/bin/mysqlslap\ --no-defaults\ --user=USER\ --password=PASS\ --host=localhost\ --port=3306\ --engine=innodb\ --concurrency=500\ --iterations=30\ --create-schema=TMP_DB\ --query="SELECT * FROM TMP_TABLE WHERE hoge = 'hoge'" Benchmark Running for engine innodb Average number of seconds to run all queries: 0.755 seconds Minimum number of seconds to run all queries: 0.702 seconds Maximum number of seconds to run all queries: 0.795 seconds Number of clients running queries: 500 Average number of queries per client: 1
的な感じでベンチマーク取れます! 500回SELECTするのを30回行い、それらの最大最小平均が取れます
オプション
オプション | 内容 |
---|---|
no-defaults | 設定ファイルに書かれたデフォルトをスキップ |
user | 接続ユーザ |
password | パスワード |
host | mysqlのhost |
port | mysqlのpoot |
engine | 対象ストレージエンジン |
concurrency | シミュレートする実行の数 |
iterations | 実行するテストの回数 |
create-schema | テストを実行するスキーマ |
query | 実行するクエリ(ファイル指定も可能) |
今回は作成済みのDB、テーブルに対して実行したのですが、 他にもテキトーなクエリを自動生成して、ベンチマークを取ることもできるようです。 というかそのほうが本来の使い方っぽいですね。。。
設定ファイルいじって性能確認する的な。
ともあれとってもお手軽!
ベンチマークというと手間かかるなーと思いがちですが、 これなら、実装後にさくっと確認できていい感じです!
もっと早く知りたかった・・・!
感謝致します。
jenkinsの表示が真っ白になった、そんな時の解決法
ある日、jenkinsにアクセスしたら、表示が真っ白になりました・・・
テキストは表示されるのですが、css,imageが404になっておりレイアウトが崩れてました。
原因
- jenkinsのuiのファイルが、/tmp以下に作られるのでサーバーの設定によってファイルが削除されるため
対応方法
- 【取り急ぎ系】jenkins再起動すればuiファイルは作りなおされます
- 【根本解決】Javaのオプションでtmpファイルを作る場所を別に指定する必要があるようです
参考にさせて頂きましたm(_ _)msnickerjp.blogspot.jp
普通にJENKINS_HOMEの下に作ってくれればいいのに・・・
感謝致します。
理論から学ぶデータベース実践入門を読んだメモ
理論から学ぶデータベース実践入門 ~リレーショナルモデルによる効率的なSQL (WEB+DB PRESS plus)
- 作者: 奥野幹也
- 出版社/メーカー: 技術評論社
- 発売日: 2015/03/10
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (9件) を見る
読んだので気になった点をいくつかメモ。
全体としては、
RDBのもととなっているリレーショナルモデルの解説と、
それを軸にRDBでよく起きる問題に対する解説がされているようなイメージでした。
タイトル通り理論が中心で読み物っぽい印象。
肝心のリレーショナルモデルは書いてあることの意味はわかるんですが、
まだまだ実感をもってはら落ちするまでできなかったので、
いつかRDBで行き詰まった時に読み直してみたいです。
以下、気になった箇所メモ。
インデックス
- インデックスは左端から順にソートされる
- 左端の文字からindexを作成していく
- WHERE LIKE "a%" => index効く
- WHERE LIKE "%a%" => index効かない
- 複合インデックスの場合も左端から順にソートされるので、カラムの並び順が重要
パーティショニング
- 範囲やキーでパーティショニングを分割
- パーティショニングが適しているケース
- キーのカーディナリティが低い場合
- それ以外の場合はインデックスで十分な場合が多い
- 最新のデータへのアクセスが多いアプリの場合、日付でパーティショニングするのは有効。パーティショニングごとにindexが作成されるので
- インデックスはクエリが決まってから検討する
- 下記の場合は、インデックスを貼らずにテーブルスキャンをしたほうがよいケースがある
- 実行頻度が低い
- テーブルのサイズが小さい
- 検索結果が非常に多くの行にヒットする
インデックスの付け方
- where句から
SELECT * FROM t WHERE col1 > 100 AND col2 = 'abc';
(col1, col2)の複合インデックスより、(col2, col1)のほうが効率がいい
col1 > 100 は膨大な数ヒットする可能性がある
- join,サブクエリでもインデックスは有効なので、joinする条件サブクエリのWHERE句からインデックスを検討する
ソート
- WHERE col1 = 100 AND col2 = 200 ORDER BY col3
という条件なら、インデックス(col1, col2, col3)でインデックスだけで解決できる
インデックスはcol1 -> col2 -> col3の順でソートされ作成されているので、
WHERE col1 = 100 ORDER BY col3
になると遅くなる
ORに対するインデックス
- WHERE col1 = 100 OR col2 = 200
の時は(col1),(col2)の2つのインデックスが必要。インデックスマージされ検索される
インデックスはカラムの並び順が重要
- 同じカラムの組み合わせでも並び順が異なるインデックスを作る時がよい時もある
カーディナリティ
- WHERE句でcol1,col2,col3が条件となっていても、col1,col2でカーディナリティが高ければ、(col1, col2)だけのインデックスで十分なケースもある。
- インデックスが増えれば、更新時のオーバーヘッドが発生するため。
インデックスは
- どのカラムを含めるべきか、カラムのカーディナリティ、テーブルのサイズ、更新時のオーバーヘッド、クエリの実行頻度から総合して考える
やはりインデックスとかすぐに実践できる系のやつが気になっちゃます><
感謝致します。
PHPerが始めるgo言語入門 〜言語仕様〜
続いてgo言語の言語仕様を確認していきます。
五月雨でアレですが。
コメントアウト
1行 // 複数行 /* */
インポート
import ( "fmt" "strings" ) import ( f "fmt" //fという別名を使う _ "os" // _は対象パッケージを使わないことをコンパイラに明示する。使っていないパッケージがあるとコンパイルエラーになる . "strings" // .でパッケージ名を省略できる )
変数の宣言
var 変数名 型 = 値 var message string = "hellow world"
複数同時に宣言
var hoge, foo, bar string = "hoge", "foo", "bar" var ( a string = "a" b = "b" c = "c" ) 同じ型なら2つ目以降は省力可能
関数内部での変数宣言
:=で型推論で宣言できる func main() { // 同じ意味 // var message string = "hello world" message := "hello world" fmt.Println(message) }
定数
constで定数に const Message string = "hello world"
初期値なしで宣言
var i int // i = 0 int => 0 float => 0.0 bool => false string => "" 配列 => 要素0の配列 構造体 => プロパティが0の構造体 その他 nil
if文
if hoge > foo { } else if hoge < foo { } else { } 3項演算子はなし if1行だけもなし
ループ
ループはforだけ for i := 0; i < 10; i++ { } いわゆるwhile的なfor i := 0 for i < 10 { fmt.Printf("i = %d\n", i) i++ }
break,continue
i := 0 for { i++ if i > 10 { break //ループ抜ける } if i % 2 == 0 { continue //偶数なら次のループへ } fmt.Println(n) }
switch文
switch i { case 1: fmt.Println("1") case 2, 4: fmt.Println("2 or 4") case 5 < i: fmt.Println("greater 5") default fmt.Println("default") } switchで比較もオッケー phpだとcaseに入ってもbreakを書かないと次のcaseへ進むが、golangは1つcaseが実行されたら、switchを抜ける 逆に1つcaseを実行されても次のcaseに行きたい時は[fallthrough]と書く switch i { case 1: fmt.Println("1") fallthrough case 2, 4: fmt.Println("2 or 4") fallthrough default fmt.Println("default") }
関数
func 関数名(引数 型) 戻り値の型 { } func sum(i, j int) { //sum(i int, j int) fmt.Println(i + j) } func sum(i, j int) int { //sum(i int, j int) return i + j } func main() { n := sum(1, 2) fmt.Println(n) //3 } func change(i, j int) (int, int) { return j, i } func main() { x, y := 3, 4 x, y = change(x, y) fmt.Println(x, y) //4 3 }
名前付きの戻り値
func div(i, j int) (result int, err error) { if j == 0 { err = errors.New("divied by zero") return // return 0, errと同じ } result = i / j return // return result, nilと同じ }
無名関数
func main() { func(i, j int) { fmt.Println(i + j) }(2, 4) }
配列
goの配列は固定長 var arr1 [4]string //4つの要素がある配列 arr[0] = "a" arr[1] = "b" arr[2] = "c" arr[3] = "d" fmt.Println(arr[0]) // a // 宣言と同時に初期化 // どちらも同じ arr := [4]string{"a", "b", "c", "d"} arr := [...]string{"a", "b", "c", "d"} 関数に配列渡す時は値渡し
スライス
可変長の配列 var s []string s := []string{"a", "b", "c", "d"} fmt.Println(s[0]) // "a" 値追加 var s []string s = append(s, "a") // 追加した結果を返す s = append(s, "b") s = append(s, "c", "d") fmt.Println(s) // [a b c d] s1 := []string{"a", "b"} s2 := []string{"c", "d"} s1 = append(s1, s2...) // s1にs2を追加 fmt.Println(s1) // [a b c d]
range
先頭から順番に処理 いわゆるforeach的な感じ arr := [...]string{"a", "b", "c", "d"} for i, s := range arr { // i = 添字, s = 値 fmt.Println(i, s) }
値の切り出し
s := []int{0, 1, 2, 3, 4, 5} fmt.Println(s[2:4]) // [2 3] fmt.Println(s[0:len(s)]) // [0 1 2 3 4 5] fmt.Println(s[:3]) // [0 1 2 3] fmt.Println(s[3:]) // [3 4 5] fmt.Println(s[:]) // [0 1 2 3 4 5]
可変長引数
phpでもこういうのできるようになりますね 可変長で引数を取ることができる func sum(nums ...int) (result int) { // numsは[]int型 for _, n := range nums { //添字は捨てる result += n } return } func main() { fmt.Println(sum(1, 2, 3, 4)) // 10 }
マップ
ハッシュ的なやつです キーと値で、格納 var month map[int]string = map[int]string{} month[1] = "January" month[2] = "February" fmt.Println(month) // map[1:January 2:February] month := map[int]string{ 1: "January", 2: "February", } fmt.Println(month) // map[1:January 2:February] 値の取得 jan := month[1] fmt.Println(jan) // January 2つ目の戻り値に値があるかboolで返してくれる _, ok := month[1] if ok { // データがあった場合 } マップから情報を消すのはdelete delete(month, 1) fmt.Println(month) // map[2:February]
かなり雑でアレですが。。。
感謝致します。
PHPerが始めるgo言語入門 〜インストール〜
これまでperlちょぴり、ほぼphpでお仕事をしてきたのですが、
このままだともろもろ幅が広がらない危機感を感じていました。
とはいえ、C,javaとかやるのもなー
rubyやってもなー
な感じで行動に移していなかったのですが、
最近go言語が広まりつつあり、
静的型付け,コンパイルで処理が高速,並列処理が容易とのことで、
phpとは違う知識がつけれそう+おいおい仕事にもつながる可能性もありそうなので、
ちょっと本腰入れて取り組んでみようと思います。
なので、何はともあれインストールから。
Go言語のインストール - golang.jp
こちらを参考にインストール
- ソースをDL、解凍
- PATH設定
- インストール確認
ソースはこちらから
Downloads - The Go Programming Language
cd /usr/local wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz tar -xzf go1.4.2.linux-amd64.tar.gz vi /etc/profile export PATH=$PATH:/usr/local/go/bin
go version go version go1.4.2 linux/ad64
でインストール完了!
続いてhello world
hello.goを作成します。
vi hello.go package main import "fmt" func main() { fmt.Printf("hello, world\n") }
実行してみます
go runでコンパイルせずに実行できるそうです。
go run hello.go >hello, world
問題なさそうです。
今回は一旦ここまで。
次回からは、
- 言語仕様の確認
- 並列処理してみる
- WEBアプリつくってみる
とかとかやっていければと思います!
以上となります。
感謝致します。
Mackerelで3分で始める簡単サーバー監視~apache,mysql,redisとか監視~
前回に引き続きMackerel的なアレを。
Mackerelで3分で始める簡単サーバー監視 - 恥知らずのウェブエンジニア
今回は監視対象にapache,mysqlなどのミドルウェアの状況を監視対象にしてみます。
手順は簡単でメジャーなミドルウェアであれば、公式のプラグインがあるので、
それをインストールして、ちょっぴり設定を修正するだけです。
公式プラグインインストール
まるっとyumでインストール
yum install mackerel-agent-plugins
ソースもgithubで公開されています。
mackerelio/mackerel-agent-plugins · GitHub
apache
mackerel-agent-plugins/README.md at master · mackerelio/mackerel-agent-plugins · GitHub
公式の通りにserver-statusにアクセスできるようapacheのconfを修正します。
Listen 1080 ExtendedStatus On <VirtualHost 127.0.0.1:1080> <Location /server-status> SetHandler server-status </Location> </VirtualHost>
/etc/mackerel-agent/mackerel-agent.confに下記のように追記します。
/usr/local/bin/mackerel-plugin-apache2 -p 1080を直接実行することで結果等も確認できます
[plugin.metrics.apache2] command = "/usr/local/bin/mackerel-plugin-apache2 -p 1080" type = "metric"
mysql
mackerel-agent-plugins/mackerel-plugin-mysql at master · mackerelio/mackerel-agent-plugins · GitHub
デフォルトだとrootで実行されるので、専用のユーザを一応作りました。
GRANT ALL PRIVILEGES ON *.* TO mackerel@localhost IDENTIFIED BY '****' WITH GRANT OPTION GRANT ALL PRIVILEGES ON *.* TO mackerel@127.0.0.1 IDENTIFIED BY '****' WITH GRANT OPTION FLUSH PRIVILEGES
またまた/etc/mackerel-agent/mackerel-agent.confに下記のように追記します。
[plugin.metrics.mysql] command = "/usr/local/bin/mackerel-plugin-mysql -username=mackerel -password=****" type = "metric"
redisとか
同じ要領で/etc/mackerel-agent/mackerel-agent.confに下記追記しました。というかコメントアウトを解除。
# Plugin for Linux [plugin.metrics.linux] command = "/usr/local/bin/mackerel-plugin-linux" # Plugin for Redis # By default, the plugin accesses Redis on localhost. # Currently AUTH password has not been supported yet. [plugin.metrics.redis] command = "/usr/local/bin/mackerel-plugin-redis"
でこれらが終わったらmackerel-agentを再起動。
sudo /etc/init.d/mackerel-agent restart
もし失敗した際は、/var/log/mackerel-agent.logを確認してください。
またApikeyがconfの下に書いてある場合は、上部に持ってくる必要があるみたいです。
これだけでリソースなど下記のようにグラフ化されます。
開発サーバーなので、動きがなくてアレですがちゃんとモニタリングできているようです。
なんて簡単・・・
ありがたいです。
感謝致します。