depを触ってみたよ
the "official experiment" dependency management tool for the Go language
というdepを触ってみた。
これがgoのライブラリ管理ツールでは公式になっていく模様。
公式ドキュメントを見ながらやってみる。
installation
macの場合、crewで入る。
$ brew install dep $ brew upgrade dep
その他の場合は下記コマンドで良さそう。
アーキテクチャ、OS、GOPATHなんかに応じてインストールしてくれる模様。
$ curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
depのコマンドを確認
こんな感じ
bash-3.2$ dep Dep is a tool for managing dependencies for Go projects Usage: "dep [command]" Commands: init Set up a new Go project, or migrate an existing one status Report the status of the project's dependencies ensure Ensure a dependency is safely vendored in the project version Show the dep version information check Check if imports, Gopkg.toml, and Gopkg.lock are in sync Examples: dep init set up a new project dep ensure install the project's dependencies dep ensure -update update the locked versions of all dependencies dep ensure -add github.com/pkg/errors add a dependency to the project Use "dep help [command]" for more information about a command.
使ってみる
今回のサンプルに使うプロジェクトを作ってそこに移動する。
このプロジェクトが他の人やプロジェクトに利用されることを想定している場合には下記の場所に作る。
$ mkdir -p $GOPATH/src/github.com/<あなたの名前>/<プロジェクト名> $ cd $GOPATH/src/github.com/<あなたの名前>/<プロジェクト名>
今回のプロジェクトが他で利用されることはないので、今回はここに作る。
$ mkdir -p $GOPATH/src/<プロジェクト名> $ cd $GOPATH/src/<プロジェクト名>
dep init
コマンドを実行し、現在のプロジェクトを解析して初期化する。
$ dep init $ ls Gopkg.lock Gopkg.toml vendor
vendorは空のディレクトリで、今後depで入るパッケージはここに。
Gopkg.toml は、現在のプロジェクトの依存関係を記述してあるファイル。
$ cat Gopkg.toml # Gopkg.toml example # # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html # for detailed Gopkg.toml documentation. # # required = ["github.com/user/thing/cmd/thing"] # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] # # [[constraint]] # name = "github.com/user/project" # version = "1.0.0" # # [[constraint]] # name = "github.com/user/project2" # branch = "dev" # source = "github.com/myfork/project2" # # [[override]] # name = "github.com/x/y" # version = "2.4.0" # # [prune] # non-go = false # go-tests = true # unused-packages = true [prune] go-tests = true unused-packages = true
Gopkg.lock は、プロジェクトが依存しているパッケージの依存関係がバージョンなんかも合わせて記載されている?
$ cat Gopkg.lock # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. [solve-meta] analyzer-name = "dep" analyzer-version = 1 input-imports = [] solver-name = "gps-cdcl" solver-version = 1
ここからどんな作業でどんな変化が生まれるをかを知るためgit管理して進める。
試しに、gin
でwebサーバーを構築して進める。
プロジェクトのルートディレクトリにapp.go
を作る。(ドキュメント丸写し)
package main import "github.com/gin-gonic/gin" func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run() // listen and serve on 0.0.0.0:8080 }
ここでプロジェクトの依存関係をインストールしてくれるというdep ensure
を叩くと、、、
$ dep ensure -v # Gopkg.lock is out of sync with Gopkg.toml and project imports: github.com/gin-gonic/gin: imported or required, but missing from Gopkg.lock's input-imports Root project is "dep_sample" 1 transitively valid internal packages 1 external packages imported from 1 projects (0) ✓ select (root) (1) ? attempt github.com/gin-gonic/gin with 1 pkgs; 22 versions to try (1) try github.com/gin-gonic/gin@v1.2 (1) ✓ select github.com/gin-gonic/gin@v1.2 w/3 pkgs (2) ? attempt github.com/gin-contrib/sse with 1 pkgs; 1 versions to try (2) try github.com/gin-contrib/sse@master ... # Bringing vendor into sync (1/8) Wrote gopkg.in/go-playground/validator.v8@v8.18.2: new project (2/8) Wrote gopkg.in/yaml.v2@v2.2.1: new project (3/8) Wrote github.com/gin-contrib/sse@master: new project (4/8) Wrote github.com/gin-gonic/gin@v1.2: new project (5/8) Wrote github.com/golang/protobuf@v1.1.0: new project (6/8) Wrote github.com/mattn/go-isatty@v0.0.3: new project (7/8) Wrote github.com/ugorji/go@v1.1.1: new project (8/8) Wrote golang.org/x/sys@master: new project
依存関係のあるパッケージをベンダー下にインストールしてきてくれる。
Gopkg.lock にも依存関係がたくさん記述されている。
vendorは重いので、.gitignoreにしておくといいかもしれない。
おわりに
プロジェクトをdep init
して、パッケージを追加したらdep ensure
する。という方針でなんとなくいいのかな。
Gopkg.tomlについてもちゃんと調べよう。
その他
goまだまだこれからという人はこの記事なんかも読んでみるとよいのかも。
CentOS6にscreen-4.6.2をインストールする
ソースを取ってくる
このサイトから、screen-4.6.2.tar.gz
のリンク先をコピーして/usr/local/src/下にダウンロードする。
$ cd /usr/local/src/ $ sudo wget https://ftp.gnu.org/gnu/screen/screen-4.6.2.tar.gz
インストール
まずは解凍
$ sudo tar -zxvf screen-4.6.2.tar.gz
インストール手順書を見てみる
$ cd screen-4.6.2 $ less INSTALL
コピペすると長いので割愛。
手順がいくつかに別れていて、手順0(./autogen.sh の実行。中身は /bin/autoreconf を実行するだけ)は普通やる必要ないみたい。
なので、手順1からやる。./configure
の実行。
ただし、そのままやると下記のようなエラーが出る。
$ ./configure ... - select can't count configure: checking for tgetent... configure: checking libcurses... configure: checking libtermcap... configure: checking libtermlib... configure: checking libncursesw... configure: checking libtinfow... configure: checking libncurses... configure: checking libtinfo... configure: error: !!! no tgetent - no screen
どうやらtgetentなる端末制御関連のライブラリがないらしいので入れよう。
$ sudo yum install ncurses-devel
もう一度 ./configure
を実行すると、最後に下のようなメッセージが出て Makefile
と config.h
ファイルが作られる。
Now please check the pathnames in the Makefile and in the user configuration section in config.h. Then type 'make' to make screen. Good luck.
sudo make
を実行すると、screen
ファイルが作られるので任意の場所に置くかシンボリックリンクを貼る。
自分は下のようなやり方で、既存のscreenをoldに変えて、新しくできたscreenにシンボリックリンクを貼った。
$ sudo make $ sudo mv /usr/bin/screen /usr/bin/screen.old $ sudo ln -s /usr/local/src/screen-4.6.2/screen /usr/bin/
以上。
あとは必要に応じて、~/.screenrc
を変えてもらうと良いかと。
多分CentOS7でもやり方は同じだと思う。
実践ハイパフォーマンスMySQLメモ
はじめに
- 実践ハイパフォーマンスMySQLを読む中で、知らなかった単語や気になったことのメモ
- この書籍では
5.5
について書かれているが、最新は5.7
なので異なる点がいくつかあるのだろうと懸念はある。
とはいえ、根本的な仕組みはそうそう変わるものではないだろう。
1章
MySQLの論理アーキテクチャ
- MySQLは3つのレイヤーに分けることができる
- 接続の処理、認証、セキュリティといったネットワークベースのほとんどのクラインアント/サーバーツールで必要となるレイヤー
- 1クライアント1スレッドが割り当てられ、スレッドは1つのコアまたはCPUに関連づけられる
- サーバーはスレッドをキャッシュするので、新たな接続の度にスレッドの作成・削除は不要
- クエリ解析、分析、最適化、キャッシュ、組み込み関数などの中枢ともいえるレイヤー
- クエリのパース・書き換え、テーブル読み取り順序の決定、使用するインデックスの選択など
- ストレージエンジンのレイヤー
- 接続の処理、認証、セキュリティといったネットワークベースのほとんどのクラインアント/サーバーツールで必要となるレイヤー
MVCC
(MultiVersionConcurrencyControl)- InnoDBの行ロックで単純な行ロックと異なっている
クラッシュセーフとは
- プロセスやマシンが正常に動作しなくなって再起動した後でも以前の状態に戻って処理を再開できるということ
2章
ベンチマークについて
- 各ベンチマークツールについて、ベンチマークの手法などについての説明
- 知識として持っておくものではなく、実際にベンチマークする時にこの章を手がかりに進めていくのがいいと思う。
- 普段の業務で使わず忘れてしまうので
3章
プロファイルについて
- パフォーマンスを最適化するにあたって必要なことが示されている
- この章も2章同様、その存在や概要を把握しておくに留め、必要になった段階でその詳細に入るとよい
4章
最適なデータ型
- 可能な限り小さいデータ型を選択する
- 例えば選手の背番号とかであれば、int(4バイト)ではなくて、tinyint(1バイト)でいいよね。
- 単純なデータ型を選択する
- 文字列型よりも整数型の比較コストが低い。
- 例えば、IPは整数型に直すのがよい
- 可能であれば
NULL
を使用しない- インデックスや値の比較を複雑にするのでできるだけ避けるべき
- とはいえ、意味不明なデフォルト定数を用いるくらいならNULLでいい
- 外部キーになりうる値には同じデータ型を使おう
- IDにはできるだけ整数を使おう。コストを下げる
正規化と非正規化
- テーブルを正規化した結果、インデックスが上手く利用できない場合には非正規化もあり。
- その場合には、参照頻度と更新が煩雑になる手間のトレードオフになるということを認識しよう
5章
プレフィックスインデックスの適切な設定
- 非常に長い文字列にインデックスをつける場合、最初の数文字にインデックスをつけることで記憶域を節約し、パフォーマンスを改善できるかも。
- 下記の方法で最適なプレフィックスの文字数を確認できる
mysql> SELECT COUNT(DISTINCT カラム) / COUNT(*) FROM テーブル; => 文字列全体でインデックスを貼ったときの選択性を出す 選択性 - カラム内の個別値の数 (カーディナリティー) をテーブル内のレコード数で割ったもの => 結果の値が高ければ高いほどSELECT時に除外できる件数が多くなり望ましい(カラムの値の重複が少ないので、SELECTされる行も少ない) mysql> SELECT COUNT(DISTINCT LEFT(カラム, 1)) / COUNT(*) AS 1, -> SELECT COUNT(DISTINCT LEFT(カラム, 2)) / COUNT(*) AS 2, -> SELECT COUNT(DISTINCT LEFT(カラム, 3)) / COUNT(*) AS 3, -> SELECT COUNT(DISTINCT LEFT(カラム, 4)) / COUNT(*) AS 4 -> FROM テーブル; => 各プレフィックスの文字数ごとの選択性を出して、文字列全体でインデックスを貼った時の値に近しい値が出たところの文字数をプレフィックスにする
複数列のインデックス
- 適切な列の順序でインデックスを設定しよう
- 何が適切かは実際に発行するクエリ、インデックスに設定される各列の値の重複が少ない(カーディナリティが高い)ものを選択しよう
カバリングインデックスとセカンダリインデックス
- 別記事にまとめる
範囲条件について
- WHERE句で範囲条件を指定できる方法は下記のように2つあり、EXPAINのtypeではどちらもrangeになるが、インデックスにおいて違いが存在する
IN()
を使ってリストで指定する方法- 1クエリの中に複数用いても、インデックスを使用することができる
- 不等号やBETWEENで範囲を指定する方法
- 1クエリの中に複数使用した場合、インデックスが効かなくなってしまう
- どちらも範囲条件を指定するものではあるが、前者の場合、等値条件を複数指定しているからだと考えられる
選択性は低いが常に検索条件やSELECTで指定されるカラムのインデックス戦略
- インデックスのプレフィックスに
IN()
で指定する
まとめ
- 単一行へのルックアップを回避しよう
- テーブルアクセスしての検索?
- ファイルソートを回避しよう
- インデックスのみを使用するアクセスを利用できるようなインデックスとクエリを選択するようにしよう
6章
スロークエリの原因
- アプリケーションが必要以上に多くのデータを取得していないか
- MySQLサーバーが必要以上に多くの行を解析していないか
- 下記3項目を確認
- 応答時間
- 処理時間と待ち時間(I/O処理の完了や行のロックなど)からなるので正確な計測は難しい
- 調査される行と返される行の数
- 調査される行の数とアクセスタイプ
- EXPLAINの記事参照
- 応答時間
- 下記3項目を確認
クエリ再構築
- 1度に処理するのは1000行など、クエリを分割する
- JOINされているクエリを複数クエリに分割する
- ロックの競合が少なくなる可能性がある
- 結合するテーブルのうち、変更頻度が高いものが1つだけの場合など、他のクエリでクエリキャッシュを使えるようになる
クエリがどのように実行されるか
大まかな流れ。強調した部分は下で簡単に補足・解説
- クライアントがSQLステートメントをサーバーに送信
- サーバーがクエリキャッシュをチェック。ヒットしたらキャッシュの結果を返す。なければ3へ
- サーバーがSQLステートメントを
解析し、前処理を行い、最適化
してクエリ実行プランを作成 クエリ実行エンジンがストレージエンジンAPIを呼び出し、クエリ実行プランを実行する
クエリ最適化プロセス(括弧内は処理する主体)
- 解析(パーサー)
- 前処理(プリプロセッサ)
- 最適化(クエリオプティマイザ)
- 最もコストの低いクエリ実行プランに変換。ただし、メモリキャッシュ、他クエリの影響などは考慮されない
- 下記のような最適化を行う
- 結合の並び替え
- OUTER JOINからINNER JOINへの変換
- 代数的等値ルールの適用
- 例) (5=5 and a>5) は、a>5 のみに
- COUNT、MAX、MINの最適化
- インデックスを有効活用すればテーブル内の全データをみなくてもよくなる
- 定数式の評価と縮小
- カバリングインデックス
- サブクエリの最適化
- 早期終了
- auto_increment の id に -1 で検索をかけるような不可能な条件などは最適化段階で終了する
第7章
業務で使われている、パーティション
、プリペアドステートメント
、クエリキャッシュ
パーティション
- (主に)特定カラムの範囲で、物理的にデータを区切る。
- WHERE句でその範囲が除外された時には、オプティマイザはそのテーブルを考慮しない
プリペアドステートメント
流れは下記の通り
プリペアドステートメントが効率がよい可能性がある理由
クエリキャッシュ
- クエリキャッシュとは
- まずSELECT文の完全な結果セットをキャッシュする。
後で全く同じクエリが投げられ、キャッシュされたデータが有効な場合にはクエリの解析・最適化・実行をスキップして、結果をキャッシュ内容から返却できる
- まずSELECT文の完全な結果セットをキャッシュする。
- クエリキャッシュの注意点
- キャッシュヒットの確認
- キャッシュヒット確認時、
クエリの解析、正規化、パラメータ化を行わない
。
なので、大文字、小文字、スペース等も全てが一致した場合にのみヒットする - 結果を生成したクエリが決定的でない限りキャッシュされない(CURRENT_DATE()などの関数が入っている場合などはキャッシュされない)
ただし、SELECT時にキャッシュの確認は行われる
- キャッシュヒット確認時、
- クエリキャッシュはいくつかの点でオーバーヘッドになる
- 読み込みクエリは開始する前にキャッシュをチェックしなければならない
- クエリがキャッシュ可能で、まだキャッシュに存在しなければ、結果を生成してから格納する
- 書き込みクエリが変更するテーブルを使用するクエリがあれば、そのキャッシュエントリを無効にしなければならない。
- キャッシュヒットの確認
参考
DockerとかCI試す用のアプリ作ったよ
Dockerで何かアウトプットをしておきたかったのと、
CircleCIを使ってみたかったので簡単な、本当に簡単なアプリケーションを作った。
githubに置いておいた。
使い方はリンク内のINSTALLATION AND LAUNCH
を参照のこと。
このアプリケーションでCIを試す
CIについてやCicleCIの登録についてなどは、こちらのブログを見て頂くとよいかと。
github、CircleCIにこのアプリケーションを登録して、CIが機能しているかを確認するにはテストコードの値を変えてみると分かりやすい。
例えばプロジェクト内のcalculator/calculator_test.goを下記のように変更してgithubにpushするとCircleCIから失敗しましたよ、ってメールが来る。
7 func TestAdd(t *testing.T) { 8 tests := []struct { 9 left int 10 right int 11 expected int 12 }{ 13 {1, 2, 3}, 14 {-1, 2, 1}, 15 {0, 0, 0}, + {1, 1, 20}, // 1 + 1 = 20 を期待するテストになっているので失敗する!! 16 } 17 18 for _, tt := range tests { 19 sum := Add(tt.left, tt.right) 20 if sum != tt.expected { 21 t.Errorf("%d is expected. got=%d", tt.expected, sum) 22 } 23 } 24 }
上記の変更をpushした後、修正した箇所を削除して再びpushするとエラーが修正されたよ、ってメールが来る。
なお、ブランチはmasterのままでも別ブランチを切ってもどちらでもよい。
アプリの見所
エラー時の表示は必見
Athenaで元データのカラム数とテーブル定義が一致しない時どのような挙動になるか
概要
ある日のデータからカラムが追加されることになった。
その時、Athenaではどのようなデータが表示されることになるのだろうか
テスト準備
price | name |
---|---|
int | string |
- 上記カラムのファイルの末尾に、country(string)のカラムを追加したcsvファイルを作成
- S3
hr1 | hr2 |
---|---|
price, name | price, name, country |
- Athena
- カラム追加前後、それぞれのテーブルを作成する
Load partitions
を実行して、Athenaにパーティションを認識させる
テスト内容と結果
テーブル毎にSELECTするカラムと読み取るパーティション、その実行結果を出すと下記の通り
- 追加前のカラムが定義されているテーブル(price, name)
SELECTするカラム / 読み取るパーティション | hr1(price,name) | hr2(price,name,country) | hr1 と hr2 両方 |
---|---|---|---|
price, name | price,nameの値が取得可能 | price,nameの値が取得できる | price,nameの値が取得できる |
price, name, country | countryが定義されていないのでエラー | countryが定義されていないのでエラー | countryが定義されていないのでエラー |
- 追加後のカラムが定義されているテーブル(price, name, country)
SELECTするカラム / 読み取るパーティション | hr1(price,name) | hr2(price,name,country) | hr1 と hr2 両方 |
---|---|---|---|
price, name | price,nameの値が取得可能 | price,nameの値が取得できる | price,nameの値が取得できる |
price, name, country | price, nameの値を取得 countryは空白で出力 |
price, nameの値を取得 | price, nameの値を取得 データにcountryがあれば取得、なければ空白 |
まとめ
- ある時点から元データのカラムは増やしてよい
- それに合わせてAthenaのテーブルカラムも増やしてよい
- 元データに存在しないカラムをSELECTしても、空白で出力されるだけでエラーにならない
- 空白があってもそのカラムに対してSUM()等の関数は実行できる
AWS 認定ソリューションアーキテクトに合格するまで
AWS認定ソリューションアーキテクト – アソシエイト (2018 年 2 月リリース)を取った。 どんなことやったかとかを書いておく。
前提レベル
- エンジニア歴1年半
- 普段ちょこちょこAWSサービスに触るものの自分で環境構築することはほぼない
- 使ってたりちょこっとでも設定したことあるのは大体こんな感じだった。
- VPC、 EC2、 S3、 CloudFront、 ELB、 Route 53、 RDS(Aurora)、 SQS、 DynamoDB、 Athena、 Elastic Cache
- いろいろ使ってはいたけど詳細は把握していなかったし、EFS、Glacier、Auto Scaling、 Lambda なんかは名前は知っているかなーくらいの素人に毛が生えたレベル。
やったこと
- 本は下2冊を時には手を動かしながら読み進める。特に上の本は必読と言っていい。
- 合格対策 AWS認定ソリューションアーキテクト - アソシエイト
- ちょっと古い本なので、最新情報が抜けていたりするけど基本的なことは変わっていないので十二分に役立つ
- 2週くらい
- Amazon Web Services 業務システム設計・移行ガイド
- オンプレからクラウドへの移行という趣旨ではあるけど、実際に手を動かしてやってみるような部分も多く、役に立った。
- 関係ない部分も多いので取捨選択が必要。特にアカウント管理、オンプレとの連携部分は流し読みでよい。
- 合格対策 AWS認定ソリューションアーキテクト - アソシエイト
- AWS クラウドサービス活用資料集を読む
- 実際にAWSでいろいろやってみる
- VPC
- プライベートサブネットのルートテーブルのデフォルトゲートウェイにNATゲートウェイを指定してみるとか(これ頻出!!)
- ユーザーデータ入れてEC2立ち上げてみる
- Auto Scaling は特に使ってみた方がいいかな。
- VPC
- 模試
- 2000円かかってしまうが、問題の感じを掴むのに受けておいた方がよい。
試験本番
- 困った時の選択肢はこれ!!
受けて思ったこと
MySQLのEXPAINの見方
EXPLAINとは
- クエリオプティマイザがクエリをどのように実行するのかを解明する手段
- どのインデックス使ってるのかなーとか確認する
- 実際に実行するとこんな感じになる
mysql> EXPLAIN SELECT * FROM covering_test WHERE key1 = 1; +----+-------------+---------------+------------+------+---------------+------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------+------------+------+---------------+------+---------+-------+------+----------+-------+ | 1 | SIMPLE | covering_test | NULL | ref | key1 | key1 | 4 | const | 2 | 100.00 | NULL | +----+-------------+---------------+------------+------+---------------+------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.01 sec)
EXPLAINをどう使うの?
- 下記2点を達成できるようEXPLAINを読み解いていこう
- 書き換える前と後でクエリの実行結果が同じになる
- EXPLAINがよりよい実行計画を表示する
各カラムについて
特に重要なのはtype
カラム
id
- 各SELECT文を識別するための通し番号で実行順序
select_type
クエリの種類を表す
- SIMPLE
- クエリにサブクエリやユニオンが含まれていない
- クエリがSIMPLEってわけではない!
- 上の例の通り
- クエリにサブクエリやユニオンが含まれていない
- SUBQUERY
- SELECTリストのサブクエリに含まれている(FROM句ではない)SELECT文
- DERIVED
- PRIMARY, UNION, UNION_RESULT
- PRIMARY - UNIONの1つ目のSELECT文であることを示す
- UNION - UNIONの2つ目以降のSELECT文であることを示す
- UNION_RESULT - UNIONの無名の一時テーブルから結果を取得するためのSELECT文であることを示す
table
partitions
- 使われているpartitionを示す
- 使われていない場合はNULL
type
MySQLがテーブル内の行を検索する方法
- ALL
- テーブルスキャンと呼ばれるもの
- インデックスが全く使われず、テーブルを最初から最後までスキャンしなければならない
- これが出た場合、改善が必要と思われる
- index
- range
- インデックスを利用した範囲検索
- WHERE句にBETWEENまたは不等号が来ている場合
- ref
- ユニーク(PRIMARYまたはUNIQUE)でないインデックスを使った等価検索(WHERE key = value)
- eq_ref, const
- PRIARY KEYまたはUNIQUE KEY(単一行であることが分かっている)が使われている
- eq_refはJOINのとき、constはそれ以外の時という違いがある
possible_keys
- 利用可能なインデックスの候補
key
- 実際に利用されたキー
key_len
- 選択されたキーの長さ
- intだったら4バイトとか
- 複合インデックスを使った場合には2つのキーの長さの合算値
- 短い方が高速
ref
- キーと比較されている値やカラムの種類
- 定数の場合には
const
- joinの場合には、結合する相手側のテーブルで検索条件として利用されているカラム
- 定数の場合には
rows
- フェッチされる行数の見積もり。あくまで見積もりなので正確な行数ではない
- ただし、サブクエリ(DERIVED)の場合は、実際に実行しないと以降の見積もりができないので正確な値が出される
- フェッチ行が全て結果行として返却されるわけではない。
- フェッチされた行からWHERE句などで絞り込みが行われる場合もある
- JOINする場合は、各クエリのrowsの値の積がフェッチされる行の見積もりになる
filtered
- テーブル条件によってフィルタ処理されるテーブル行の推定の割合
- typeがRANGE, index, rage, index_mergeの時、利用されるようだがよく分かっていない
Extra
上記カラム以外の情報が出力される
その他っぽいけどとても大事
- Using index
- カバリングインデックスが使用されているので、テーブルアクセスが発生していない
- Using where
- テーブルから行をフェッチした後に絞り込みが行われている
- フェッチ時点で行数制限したいので、WHERE句でインデックスを適切に利用する等何らかの改良の余地があると思われる
- Using temporary
- GROUP BY や ORDER BY でソートするために一時テーブルを使用することを意味する
- Using filesort
- インデックスでのソートではなく、ソートアルゴリズムが使われている
- Range checked for each record (index map: N)
- JOINにおいてrangeまたはindex_mergeが利用される