- 投稿日:2020-01-12T18:20:38+09:00
エンジニア研修
概要
今回弟がエンジニアデビューするということで、macbookAir(gold)を買ってあげました。
これから9か月間、私の方で研修をおこない、それなりのエンジニアになってもらおうかと思います。そこで弟のように、エンジニアを始めたばかりの人の参考になるように、「研修内容」、「弟が躓いた箇所」や「参考文献など」を記事にしていこうかと思います。
普段私は自分のブログサイトで発信していましたが、誰も見てくれないので、qiitaに書いていくことにしました。
https://campbel.love/が私のサイトです。たまには見てくださいな(笑)弟はそこまで忍耐力もなく、また、ほとんど初心者なので「挫折をしないカリキュラム」、「スムーズな理解」に重点を置くつもりです。まさにゆとり!
なので、少し遠回りをしてしまうかもしれません。
例えば、Dockerを用いてもらいたいけど、初学者の弟には難しいのでMampから始めてもらう。みたいな。(最終的にはdockerにしてもらいますが。)偉そうにカリキュラムは組みましたが、私自身も勉強途中で全部を理解はしていません。弟と一緒に勉強して知識を高めていきたいと思っています。
*もし、こんなやり方の方がいい、これは間違っているなどありましたら、コメントをお願いいたします。弟と私のために。私は文章を書くのがすこぶる苦手なので、わかりづらい事や誤字脱字もあるかと思いますが、どうぞよろしくお願い致します。
予定のカリキュラム
文法の理解などは基本はdotinstallをやってもらいます。(有料なので私が支払うことになりそう。。。)
わからないことがあれば随時きくように。1ヶ月目、2ヶ月目
・php、html、css、js、mysqlを理解する。(jsから初めてもらおうかなと)
・mampの設定
・macの操作、mampになれる。3ヶ月目、5ヶ月目
・jqueryもしくはvueをつかう。vueが使えるようになったら最高。ちなみに私は使用したことがない。
・gitを使えるようにする。
・local環境下でいいのでlaravelでサイトを作れるようにする。
「掲示板的なやつ」もしくは「画像投稿サイト」でいい。
デザインパターンはしっかり行う。
リレーション、トランザクションもしっかり行こなう。
ログイン認証もしっかり行う
時間があればrest api作成も行う。
・hostsの理解などここらへんで一区切り。。。
6ヶ月目、7ヶ月目
・cicdを使う(cercleciでいいかと)
・awsを使う
・laravelのテスト仕様書も書けるようにする。8ヶ月目
・localとawsでdockerを使う。9ヶ月目
kubernetesを使用する??これは未定。。。これでかなりレベルの高いエンジニアであると僕は思うが、参考にしているエンジニアチャンネルでは、これが最低ラインだと言っていました。。。(kubernetesは除く)
エンジニアの敷居が上がってきているのかしら?٩( ᐛ )و
しかし、専門学生が2年通うよりも全然最強だと思います!!
ちなみに私はこれらのことを、もちろんこれだけでなく他の勉強もしながらですが、数年かけました。それを弟は9ヶ月で行うため、厳しい道のりになるとおもわれます。弟よ!がんばれ〜!!( ^ω^ )私の課題として、「awsでdockerを使用する」、「kubernetesを使用する」はまだやったことがないので、できるようにしておきます!
なぜmacなのか
一言で言うと使っている人が多いから。
他には、サーバーではlinuxを使用することが多いが、macはwinよりもlinuxに近いからとか、bashが使えるからとか、かっこいいから。賛否両論だと思いますが、とにかくmacを買うことをお勧めします。
高いなと思うかもしれませんが、分割での購入も可能で、2年の分割だと利子はなんと0円です。
あと学割があって最大22000円引きで購入が可能。2020年2月からは新学期キャンペーンで3万ほどのヘッドフォンがついてきますよ!お得です!
参考1日目はマックの設定
1 appleidの作成、osが最新かどうかのチェック
2 アプリのダウンロード(詳細は以下)
3 chromeの拡張のダウンロード(詳細は以下)macにダウンロードするアプリ
ブラウザ
「こんなにいらないやろ」と思うかもしれないが、”最強のエンジニア”には必要である。(アプリ欄を見てこれらがないと笑われてしまう。(嘘))
chrome
firefox
opera開発に必要なアプリ
サイバーダッグ: サーバーのファイルをいじれる
iterm2: ターミナルの拡張版
sequel pro: mysqlをいじる
vs code: エディタ(高級なメモ帳)
postman: apiを可視化
xcode: 主にアイフォンのアプリを作成するのに使用。アイフォンのアプリを作成しなくとも必要。
mamp: mac、apache、mysql、phpの略。windowsだとxamp。パソコン内に仮想のサーバーを立てることができる。
mampでの開発は時代遅れのゴミで、本来ならば(というよりできるエンジニアは)Dockerを使うべきだが設定はmampの方が断然楽なので、初め(6ヶ月くらい)はmampで対応する。
composer: phpのライブラリ環境コマンド。これは必須。なくても開発はできるが、使用していないのはゴミエンジニアである。チャットアプリ
line: line
chatwork: よく使われるチャットツール
slack: よく使われるチャットツールその他便利なアプリ
app cleaner: アプリをきれいに削除できる
cd to: フォルダから直で移動できる。
clipy: コピーしたものの履歴が残る。数百円なので絶対に入れた方がいいと思われるアプリの一つ。使ったら世界が変わったように感じるほどの代物。これらはまだ使用しないと思われるので、まだインストールしなくていい
brew cask
git
anyenv: phpしか使わないならば、いらない。python、node.jsをやる場合は入れた方がいい。chromeにダウンロードする拡張の機能
開発はおもにchromeで行うため、chromeの設定はとても大事です。
ダウンロード先はここ
https://chrome.google.com/webstore/category/extensions?hl=ja開発に必要なアプリ
Clear Cache: キャッシュの削除
EditThisCookie: クッキーの編集
Page load time: ページが表示されるまでの時間計測
Quick Javascript Switcher: jsのオンオフ切替。1クリックでできるため、めちゃめちゃ便利です。あると便利なアプリ
Wappalyzer: 自分が閲覧したサイトがどの技術で作られているか確認ができる。
Google のクロム ™ のための時計: chromeに時計を表示させる。
ブックマークサイドバー: ブックマークがマウスオーバーで開ける。お勧めの設定は「マウスを左に持っていき右クリックで表示させる。」個人的にお勧めなアプリ
Douga Getter: 動画のダウンロード
ストリームレコーダー: 動画のダウンロードとりあえず1日目はここまで。お疲れ様です。
- 投稿日:2020-01-12T18:02:13+09:00
VBAフォーム、DB接続クラス化入門①
【はじめに】
医療事務から30代未経験でSIerへ転職して1年経過したため(保守運用)、この一年勉強して自分がググる際に、この情報もっとあったらいいなと思ったことを備忘録として登録します。
配属しいている現場はVB6を使用したレガシーな現場である為、書き方が古かったりするかもしれないが、その点はまだ無知な点が多い為、ご了承ください。
熟練者から見たらまだまだ、冗長化されている部分もあるかと思いますが、あくまで入門者向けの方に参考していただければと思います。自宅でも勉強構築できる、なおかつ互換性のあるVBAにてCRUDができる機能を実装します。
そもそもプログラミング自体ほぼ皆無だった状態からのため、レガシーだろうが、何だろうが、まずはプログラミングについて理解を深める意味で初めてQiitaに投稿します。
今回はDB接続~テーブルに登録してあるデータをSELECTして取り出したデータをリストに表示するところまでを備忘録として記載します。【環境】
- OS:Windows8.1
- Excel 2013
- エディタ:VBE
- ローカル開発環境:xampp(過去にPHPのCRUDを勉強するためにxamppを用いてDB構築したため利用)
【主な機能について】
DB登録されたID、UserName、Email、登録年月日をテキストボックスに入力して、データ表示ボタンをクリックすると、リストボックスに登録データを表示する。
※1.登録年月日の入力は必須
※2.各バリデーションチェックのソースコードを載せると長くなるため、記載しておりません。フォームのイメージは以下
メイン画面(現状データ検索ボタンしかないが、データ作成、更新、削除を追記予定)
frmMain
データ検索ボタンをクリックすると以下のフォームを表示
テキストボックスのオブジェクト名は以下の通り
- ID⇒ID_txt.Text
- UserName⇒UserName_txt.Text
- Email⇒Email_txt.Text
- 登録年月日(from)⇒InsDate_from_txt.Text
- 登録年月日(to)⇒InsDate_to_txt.Text
チェック項目
ID UserName 登録年月日(from) 登録年月日(to) 入力 任意 任意 任意 必須 必須 最大文字数 11 25 255 8 8 ※DB設計時、細かく設定しておらず、Emailの最大文字数は255のままになっている
改めて適切なchar数に設定したいと思う【Create Table】
DBへ登録するための、テーブル作成
データベース名:bbs
テーブル名:test_user_data_hed
※データは適当にINSERTして登録してもらえればと思います。
test_user_data_hed.sqlCREATE TABLE bbs.user_data_hed ( ID INT(11) AUTO_INCREMENT NOT NULL PRIMARY KEY, USER_NAME VARCHAR(25) NOT NULL, EMAIL VARCHAR(35) NOT NULL, STATUS INT(1) NOT NULL, INS_DATE VARCHAR(14) NOT NULL, UPD_DATE VARCHAR(14) NOT NULL ); /* STATUS = 1:通常、9:論理削除 */【ソースコード】
frmMain'-------------------------------------------------------------------- 'データ検索フォーム表示 '-------------------------------------------------------------------- Private Sub frmTableSearch_Click() frmSearch.Show End SubfrmSearchOption Explicit '-------------------------------------------------------------------- '変数宣言 '-------------------------------------------------------------------- Private lstrId As String Private lstrUser_name As String Private lstrEmail As String Private lstrStatus As String Private lstrInsDatefrom As String Private lstrInsDateTo As String '-------------------------------------------------------------------- '機能:bbsへDB接続 'test_user_data_hedに登録されているテーブルデータをリストへ表示するためのトリガー '-------------------------------------------------------------------- Public Sub select_cmd_Click() Dim dbconnect As mysql_connect Dim ladoRs As ADODB.Recordset 'ローカルレコードセット変数 Dim ConnectFlg As Boolean '接続成功: True 接続失敗:False Dim lstrSQL1 As String 'ローカルsql格納変数 Dim lintroop As Integer 'ループ変数 '例外処理⇒以下の記述でエラーが発生した場合にはエラーメメッセージ表示 On Error GoTo ErrHandler_End lstrId = ID_txt.Text lstrUser_name = UserName_txt.Text lstrEmail = Email_txt.Text lstrInsDatefrom = InsDate_from_txt.Text lstrInsDateTo = InsDate_to_txt.Text 'mysqlクラスへ接続 Mysql_connectクラスのdbconnectをインスタンス化 Set dbconnect = New mysql_connect 'Mysqlクラスのmysql_connectメソッド内で接続処理を行い、接続成功の場合Trueを返す ConnectFlg = dbconnect.mysql_connect 'selectすべきSQLを記述 lstrSQL1 = "" lstrSQL1 = "SELECT ID" lstrSQL1 = lstrSQL1 & ",USER_NAME" lstrSQL1 = lstrSQL1 & ",EMAIL" lstrSQL1 = lstrSQL1 & ",STATUS" lstrSQL1 = lstrSQL1 & ",INS_DATE" lstrSQL1 = lstrSQL1 & ",UPD_DATE" lstrSQL1 = lstrSQL1 & " FROM bbs.test_user_data_hed" '論理削除は表示しない lstrSQL1 = lstrSQL1 & " WHERE STATUS <> '9'" 'ID入力がある場合は、 If Trim(lstrId) <> vbNullString Then lstrSQL1 = lstrSQL1 & " AND ID ='" & lstrId & "' " End If 'USER_NAME入力がある場合は、 If Trim(lstrUser_name) <> vbNullString Then lstrSQL1 = lstrSQL1 & "AND USER_NAME ='" & lstrUser_name & "' " End If 'EMAIL入力がある場合は、 If Trim(lstrEmail) <> vbNullString Then lstrSQL1 = lstrSQL1 & "AND EMAIL ='" & lstrEmail & "' " End If lstrSQL1 = lstrSQL1 & " AND INS_DATE >='" & lstrInsDatefrom & "000000" & "' " lstrSQL1 = lstrSQL1 & " AND INS_DATE <='" & lstrInsDateTo & "235959" & "' " 'DB接続状態である場合に、Mysqlクラスのmysql_selectメソッドへアクセスし、上記で記述したSQLとリストオブジェクトを引数として渡す。 If ConnectFlg = True Then Set ladoRs = dbconnect.mysql_select(lstrSQL1, select_data_List) End If 'インスタンス解放(確保していたメモリ領域を0にする) Set dbconnect = Nothing Set ladoRs = Nothing Exit Sub ErrHandler_End: Set dbconnect = Nothing Set ladoRs = Nothing Call MsgBox ("DB接続エラー" & vbCrLf & _ "ErrNo:" & Err.Number & vbCrLf & _ "Err内容:" & Err.Description _ , vbExclamation, "Error:Sub dbconnect") End Sub Private Sub Exit_cmd_Click() Unload frmSearch Load frmMain End Sub Private Sub UserForm_Initialize() ID_txt.Text = vbNullString UserName_txt.Text = vbNullString Email_txt.Text = vbNullString InsDate_from_txt.Text = vbNullString InsDate_to_txt.Text = vbNullString End SubMysql_connect.clsOption Explicit Private adoCon As ADODB.Connection 'データベースアクセスインターフェースオブジェクト(ActiveX Date Objects) Private adoRs As ADODB.Recordset 'レコードセット変数 Executeで実行したSQLで取得したレコードをセット Private adoCmd As ADODB.Command 'SQL実行コマンドオブジェクト Private Const DSN = "ExcelDB" 'DataSourceName Private Const Database = "bbs" '接続先DB '-------------------------------------------------------------------- 'DB接続class 'mysqlへの接続 '【引数】なし 'mysql_connect True:接続成功 False:接続失敗 '-------------------------------------------------------------------- Public Function mysql_connect() As Boolean 'adoコネクション作成(データベース接続オブジェクト) Set adoCon = New ADODB.Connection On Error GoTo ErrHandler 'サーバから取得したカーソルをクライアント側に置いて作業する。 adoCon.CursorLocation = adUseClient 'DB接続、ODBCを使用してMysqlへ接続 'Mysql接続(接続文字列 ⇒ DSN) adoCon.Open DSN '接続成功 mysql_connect = True 'エクセル画面の左下、ステータスバーにDB接続成功した場合は、以下の文字列を表示 Application.StatusBar = "DB接続成功!! " & "接続先:" & Database Debug.Print "接続先:" & "bbs" Exit Function ErrHandler: '接続失敗 mysql_connect = False Set adoCon = Nothing Application.StatusBar = "DB接続失敗!! 調査を依頼してください。" Call MsgBox("DB接続時エラー", vbExclamation, "Error:Function mysql_connect") End Function '-------------------------------------------------------------------- '【機能】sql文実行(SELECT) '【引数】 lstrSQL ' select_date_List '【戻り値】adoRs 問い合わせしたSQLのレコードを返す '-------------------------------------------------------------------- Public Function mysql_select(ByVal vstrSQL1 As String _ , ByVal vobjList As MSForms.ListBox) As ADODB.Recordset Dim lintloopRcdCnt As Integer 'レコード取得ループ変数 Dim lRecordCnt As Long 'レコードカウント数取得変数 'On Error GoTo 以下で予期せぬエラーが発生した場合、ErrHandlerのラベルまで飛び、エラー発生時の処理およびメッセージを表示してFunctionを抜ける On Error GoTo ErrHandler 'DBアクセスのタイムアウト時間(時間切れ)を10分に設定 adoCon.CommandTimeout = 60*10 Set adoCmd = New ADODB.Command 'SQLコマンドオブジェクトインスタンス化 adoCmd.ActiveConnection = adoCon 'コマンドオブジェクトのActiveConnectionプロパティを使用して、現在開いているDBと関連付け adoCmd.CommandText = vstrSQL1 '実行するSQLを格納 コマンドテキストにSQLステートメントを定義する(文字列にストアドプロシージャの文字列を設定するとストアドを実行する) Set adoRs = New ADODB.Recordset 'レコードセットオブジェクトインスタンス化 'クエリーの結果を格納するRecordsetオブジェクト変数 'コマンドテキストに格納されたSQLをExecuteメソッドを実行し、adoRsへ格納する Set adoRs = adoCmd.Execute Debug.Print vstrSQL1 'SQLで問い合わせて取得したデータをリストボックスへ表示 With vobjList .Clear 'リストの項目を初期化するためクリア .ColumnCount = 3 'リストに表示するカラム数 .ColumnWidths = "30;60;100" 'リストに表示する幅 'adoRsへ格納したSQLステートメントをループさせてリストへ取り出す処理 Do Until adoRs.EOF .AddItem "" 'レコードセットの列数を取得して、ループ For lintloopRcdCnt = 0 To adoRs.Fields.Count - 1 'レコードの値が存在する場合は、レコードの値をリストへ表示する If Not IsNull(adoRs(lintloopRcdCnt).Value) Then 'adoRsのレコードデータをリスト(行、列)をループして追加(Listの先頭インデックスは「0」スタートのため、-1をする⇒(List(0),レコード列の 'カウント数)に対して、レコードの値を代入していっている) .List(.ListCount - 1, lintloopRcdCnt) = adoRs(lintloopRcdCnt).Value End If Next '1行目のレコード取り出しが完了したら、次のレコードへ adoRs.MoveNext Loop End With 'レコードカウント数を取得し、0件だった場合はエラーメッセージ lRecordCnt = adoRs.RecordCount If lRecordCnt = 0 Then Call MsgBox("該当のデータは存在しません。", vbQuestion) Exit Function End If 'レコードセットを返す Set mysql_select = adoRs Set adoCmd = Nothing Set adoRs = Nothing 'Connectionオブジェクトを閉じて、それに関連するRecordsetオブジェクトも閉じる adoCon.Close '閉じただけでは確保しているメモリは解放されない為、Nothingで解放する。 Set adoCon = Nothing Exit Function ErrHandler: 'レコード取得時に予期せぬエラー Set adoCmd = Nothing Set adoRs = Nothing adoCon.Close Set adoCon = Nothing Call MsgBox("DBレコード取得時エラー" & vbCrLf & _ "ErrNo:" & Err.Number & vbCrLf & _ "Err内容:" & Err.Description _ , vbExclamation, "Error:Function mysql_select ") End Function以上がMysqlへ接続するためのソースになるが、ソースとその説明を別々に記載するとわかりづらいかと思い、すべてコメントに記述してみた。
【参考資料】
ODBCによるMysql接続は上記サイトを参考に、コントロールパネル⇒システムとセキュリティ⇒管理ツールの順で進み、ODBCデータソース(32ビット)にて、ユーザーDSNを追加し、
- Data Source Name: xxxxxx
- TCP/IP: localhost or 127.0.0.1
- Port: 3306
- User: xxxxxx
- Password: xxxxxx
- Database: xxxxxx
上記を設定後、テストボタンをクリックして、「Connection Successful」が出れば接続テストは完了です。
PHP超入門はクラスを学ぶ上で大変参考にさせていただいた記事です。
PHP言語に限らず他の言語でも参考になるものと思っています。こちらの記事も大変参考にさせていただいた記事です。クラス、Propertyの使い方など(この点については使いどころも部分がまだまだ自分も未熟のため、本投稿のソースはPropertyを使用していませんが…)実際にデバック操作することで理解を深められる内容となっていました。
どこを分割するか、どうやって分割するか、についてのコツがわかりやすくまとまっています。
今でも何度も読み返すことの多いブログです。オブジェクト指向について未だに理解が不十分であるが、そもそもを理解するために、良書といわれている上記本を参考し、クラスをインスタンス化した場合のメモリの確保などについて学んだ本。
再度読み返し、理解を深めたい。
- 投稿日:2020-01-12T15:37:24+09:00
database接続の手書き入力について
databaseの手書き接続まとめ
環境
xampp
mysqlとApacheが必要です。なぜこの記事を書こうと思ったのか?
主に3つあります。1.databaseのPDO形式が多く手書き入力のサイト記事が全くないこと。
2.Qiitaにいつもお世話になっているから
3.いつでもアクセスできるように記事として残しておきたい
登録するためのdatabase
まずここで登録するdataを確認
database名:bowring
table:player
id: auto_increment,int型
name:varchar型database接続:基本構文(INSERT,UPDATE,DELETEで有効)//mysqli_connectはホスト名,ユーザー名,パスワード,database名の順で記述すること $cn = mysqli_connect("localhost", "root" , "" , "bowling" ); //utf8は言語を設定:utf-8という記述は× mysqli_set_charset($cn,'utf8'); //sql文記述 $sql = "INSERT INTO player (name) VALUES ('hogehoge');"; //queryで実行するという意味 mysqli_query($cn,$sql); mysqli_close($cn);VALUESの後に注目
varchar型を用いる場合はシングルクォーテーションを含み、記述すること。
私はこの処理に2時間悩んでいました(泣)varchar,int型での注意$id = 1; $name = 'hogehoge'; //db接続 $cn = mysqli_connect("localhost", "root" , "" , "bowling" ); mysqli_set_charset($cn,'utf8'); $sql = "INSERT INTO player (id,name) VALUES ($id,'$name');"; mysqli_query($cn,$sql); mysqli_close($cn);SELECT文で全件取り出す。
SELECT文$cn = mysqli_connect("localhost", "root" , "" , "bowling" ); mysqli_set_charset($cn,'utf8'); //プレイヤーテーブルから全件取り出し $sql = "SELECT * FROM player"; //実行して$resultの中に入れる $result = mysqli_query($cn,$sql); //空配列 $player_list = []; //表示結果(フィールド)をひとつづつループで回し、$player_listに代入する while($row = mysqli_fetch_assoc($result)){ $player_list[] = $row; } mysqli_close($cn); //全件表示;配列で表示するため、foreachで回す foreach($player_list as $player_lists){ echo $player_lists['id'].$player_lists['name']."<br>"; }もっと楽にできるfunction処理
皆さん、functionをご存じでしょうか?
知らない人もいるとは思いますのでこちらの記事を参考にどうぞ!!!
https://techacademy.jp/magazine/4925簡単にご説明すると関数を呼び出すだけで何百行という処理を一行で書くことが可能になります。
database接続:基本構文(INSERT,UPDATE,DELETEで有効)function set_player($sql,$host , $db_user , $db_pass , $db){ $cn = mysqli_connect($host , $db_user , $db_pass , $db ); mysqli_set_charset($cn,'utf8'); mysqli_query($cn,$sql); mysqli_close($cn); } //ここにsql文と接続所を記述するだけで呼び出し可能: set_player("INSERT INTO player(id) VALUES(1)","localhost" , "root","","bowling");##SELECT文で全件取り出す。function get_player($host , $db_user , $db_pass , $db ){ $sql = "SELECT * FROM player; $cn = mysqli_connect($host , $db_user , $db_pass , $db ); mysqli_set_charset($cn,'utf8'); $result = mysqli_query($cn,$sql); $player_list = []; while($row = mysqli_fetch_assoc($result)){ $player_list[] = $row; } mysqli_close($cn); //returnで返すことによってより広範囲で可能 return $player_list; } // $player_list = get_player("localhost" , "root","","bowling"); //全件表示;配列で表示するため、foreachで回す foreach($player_list as $player_lists){ echo $player_lists['id'].$player_lists['name']."<br>"; }SQLインジェクション対策についての手書き入力
また、文字の種類にも注意することi 対応する変数の型は integer です。
d 対応する変数の型は double です。
s 対応する変数の型は string です。
b 対応する変数の型は blob で、複数のパケットに分割して送信されます。SQLインジェクション対策function set_player($host , $db_user , $db_pass , $db , $name){ $cn = mysqli_connect($host , $db_user , $db_pass , $db ); mysqli_set_charset($cn,'utf8'); $stmt = mysqli_prepare($cn,"INSERT INTO player (name) VALUES (?);"); $sql = mysqli_stmt_bind_param($stmt,'s',$name); mysqli_stmt_execute($stmt); mysqli_stmt_close($stmt); mysqli_close($cn); } //set_player("localhost" , "root","","bowling","hogehoge");
- 投稿日:2020-01-12T13:45:02+09:00
mysql DB作成におけるメモ
ど忘れしていたので、個人的メモ。
rails db:createできない時は以下の4点を確認。
・mysql側にuserが作成されているか
・そのuserはpasswordがあるか
・database.ymlにusernameとpasswordの記載があるか
・そのuserは権限付与されているか
- 投稿日:2020-01-12T08:36:16+09:00
ソートを制してWebアプリ一覧画面の表示を速くする
対象読者
- Webアプリケーションエンジニア
- SQLチューニングの基本を学習ずみ
使用環境
- MySQL 5.6
一覧表示の抱えるリスク
webアプリケーションにおけるデータの一覧表示処理は、SQLが遅くなる可能性の高い処理です。
時間が経つとともにデータが増え、複数のテーブル結合で走査件数が多くなりやすく、大抵の場合、ソート機能を備えています。
このソート処理は、走査件数が多くなるほどにコストが非常に高まってくる問題児です。
この記事ではそんなソート処理への対策について、自分自身の理解を深めるためにも内容をまとめてみたいと思います。大規模のデータの全件を処理するとコストが高いので、ページングなどでLIMIT句をつけると良いと考えても、LIMIT句が適用されるのはSQL評価順序の最後なので、その前に処理時間のかかる箇所があると改善されません。ORDER BYもその一つになります。
遅い箇所を調べていくのですが、SQLがORDER BYしているならば、まずはORDER BY句の列にインデックスが定義され、それが使えているかどうかをチェックするのが良いと思います。主観的には扱いを間違いやすい場所で、負荷も非常に高いからです。インデックスとソートの関係について
インデックスは並び替えられた状態でデータを持っているため、Order By句に指定したインデックスからデータをフェッチできている場合は、その時点でソートは完了します。
しかし、そうでない場合は、毎回メモリ内でソート(クイックソート)を行うので、データ量が多くなったとき、大変遅くなってしまいます。
そのため、ソート列にインデックスを定義することと、それが使用されるようにすることが対処の要点になります。悪玉ソート処理の確認
explainステートメントを発行したとき、key欄に並び替え列のインデックスの表示がなく、Extra欄に「filesort」表示があるなら、インデックスが使用されずにDBサーバのメモリ内でソートされています。これは年老いてから(レコードが増えてから)の癌となるソートです。
データ量の多くなった時にshow profileステートメントで、「Creating sort index」の項を確認すれば、相当な時間がかかっていることが確認できると思います。
※データ量が少ないときはインデックスが使われないので「filesort」表示されますが、これは問題ありません。複合インデックスが必要でないか
並び替え列にインデックスが使われていなければ、まずWHERE句等でテーブルに対して先に別のインデックスが使われていないかを確認します。MySQLの場合、1テーブル1インデックスしか使うことができないためです。
先に別のインデックスが使われてしまっている場合、複合インデックスを追加できるかどうか検討しましょう。WHERE句はORDER BY句より先に評価されるので、WHERE句の列, ORDER BY句の列の順番で定義します。複合インデックスで並び替えるSELECT * FROM t1 LEFT JOIN t2 ON t1.t2_id = t2.id WHERE t1.type = 1 ORDER BY t1.日付 DESC /* t1.type単体のインデックスが存在する場合、t1.日付のインデックスはNG t1.type, t2.日付の複合インデックスならOK */ORDER BYは駆動表の列で指定されているか
他に使われるインデックスがない状態でORDER BY句のインデックスが使われていなければ、その並び替え列が駆動表の列で行われているかどうかを確認します。駆動表は、LEFT JOINであれば先に指定したテーブルです。
結合しているクエリで並び替え列を、駆動表の列でなく、内部表の列で指定すると、インデックスを定義していても並び替えに使われず、explainのExtra欄に「filesort, using temporary」と表示されてしまいます。JOIN先のテーブル(内部表)で並び替えはNGSELECT * FROM t1 LEFT JOIN t2 ON t1.t2_id = t2.id ORDER BY t2.日付 DESCJOINは駆動表が親ループの集合となるので、並び替えされたインデックスフェッチで親ループの集合が作成できると、並び替えの必要がなくなりますが、内部表のインデックスフェッチでは、そこで並び替えは完了できません。結合が終わってから改めて並び替え(一時テーブルを作成してクイックソート)する必要があります。
以下の疑似コードで説明します。ネステッドループ結合の疑似コード/* 駆動表の作成にORDER BY句のインデックスを参照できると、そこで並び替え完了 */ t1 = indexFetch(t1, "日付") for each row1 in t1.filter(it => { return it.col == joinKey } { /* 内部表の作成でORDER BY句のインデックスを参照しても、全体の並び替えはできない t2 = indexFetch(t2, "日付") */ for each row2 in t2.filter(it => { return it.col == joinKey } { sendClient(row1, row2) } }SQLでの評価順では、ORDER BY句はJOIN句よりも後ですが、ORDER BY句の定義であってもそのインデックスが使える場合はインデックスフェッチにより、「先に並び替え」が実行されるというのがポイントかと思います。
全件の処理ではなく、インデックスの他に結合条件・検索条件でフェッチできる状況では、
インデックス → 結合 → 検索
の順番で絞り込み処理がされるので、後続の負担が減らせるよう早い段階での絞り込みができれば、より効果的となります。
全体のフェッチにかかった時間は、show profileを実行し、「Sending data」の表示で確認することができます。ちなみに、外部結合ではなく内部結合では、駆動表がオプティマイザの判断次第になるため、駆動表を固定するために、INNER JOINの代わりにSTRAIGHT_JOINを使った方が良いです。
内部結合でもSTRAIGHT_JOINなら、t1は駆動表になることが保証されるSELECT * FROM t1 STRAIGHT_JOIN t2 ON t1.t2_id = t2.id ORDER BY t1.日付 DESCそれでは、どうしても内部表の列で並び替えする必要がある場合はどうすれば良いでしょうか。
その場合は、対処療法になりますがサブクエリで、先に内部表にあたるテーブルの並び替えを済ませ、合わせてLIMITを行うことが考えられます。その結果と、元の内部表を結合します。並び替えとLIMITをサブクエリで行うパターンSELECT * FROM t1 LEFT JOIN ( ( SELECT * FROM t2 ORDER BY 日付 DESC LIMIT 0, 20 ) as sorted_t2 INNER JOIN t2 ON sorted_t2.id = t2.id ) as tmp_t2 ON t1.t2_id = t2.idtmp_t2はサブクエリの結果による一時テーブルのため、t1との結合にインデックスを使うことはできなくなりますが、並び替えとそこからの頭読み出しが完了し、件数が少なくなっているため、問題ではなくなります。
ただ、ページング用のLIMITを自前で指定する必要があるので、WebアプリケーションのORMによるSQL構築は適さなくなります。GROUP BYにインデックスを使えているか
GROUP BYによっても、暗黙的にソートが発生します。サブクエリで集計の一時テーブルを作り、駆動表と結合しているケースを例にすると、一時テーブル内でGROUP BYするカラムのインデックスを作成して、ソートを防ぐことができます。
駆動表と一時テーブルとの結合条件にインデックスは使えないため、GROUP BY時のインデックスフェッチは使いたいところですが、もし何らかの理由でインデックス再設計を避けたい場合は、ORDER BY NULL指定をすることで、GROUP BYによる暗黙ソートを止めることできます。(MySQL8.0ではこの暗黙ソートが無くなるとのことです)SELECT * FROM t1 LEFT JOIN ( /* t2にadd indexしたくない時、並び替えを防ぐ */ SELECT * FROM t2 GROUP BY 日付 ORDER BY NULL ) as grouping_t2 ON sorted_t2.id = t2.id今回は件数の多いデータを処理するために、まずソート処理の問題解決を図ることが効果的であることを書きました。
ちょうどSQLチューニングネタで記事を書きたいと思っていたところに、こちらの素晴らしい記事に触発されました。。
ソート以外にも書くつもりでしたが、まとまらなかったので、一旦打ち切ることにします。
また機会があれば書いてみたいと思います。参考文献
http://nippondanji.blogspot.com/2009/03/using-filesort.html
https://www.slideshare.net/yoku0825/whereorder-by
- 投稿日:2020-01-12T08:36:16+09:00
Order Byを制して一覧画面の表示を速くする
対象読者
- Webアプリケーションエンジニア
- SQLチューニングの基本を学習ずみ
使用環境
- MySQL 5.6
一覧表示の抱えるリスク
webアプリケーションにおけるデータの一覧表示処理は、SQLが遅くなる可能性の高い処理です。
時間が経つとともにデータが増え、複数のテーブル結合で走査件数が多くなりやすいことに加え、大抵の場合、ソート機能を備えているからです。
このソート処理は、走査件数が多くなるほどにコストが非常に高まってくる問題児です。
この記事ではそんなソート処理への対策について、自分自身の理解を深めるためにも内容をまとめてみたいと思います。大規模のデータの全件を処理するとコストが高いので、ページングなどでLIMIT句をつけると良いと考えても、LIMIT句が適用されるのはSQL評価順序の最後なので、その前に処理時間のかかる箇所があると改善されません。
遅い箇所を調べていくのですが、SQLがORDER BYしているならば、まずはORDER BY句の列にインデックスが定義され、それが使えているかどうかをチェックするのが良いと思います。主観的には扱いを間違いやすい場所で、負荷も非常に高いからです。インデックスとソートの関係について
インデックスは並び替えられた状態でデータを持っているため、Order By句に指定したインデックスからデータをフェッチできている場合は、その時点でソートは完了します。
しかし、そうでない場合は、毎回メモリ内でソート(クイックソート)を行うので、データ量が多くなったとき、大変遅くなってしまいます。
そのため、ソート列にインデックスを定義することと、それが使用されるようにすることが対処の要点になります。悪玉ソート処理の確認
explainステートメントを発行したとき、key欄に並び替え列のインデックスの表示がなく、Extra欄に「filesort」表示があるなら、インデックスが使用されずにDBサーバのメモリ内でソートされています。これは年老いてから(レコードが増えてから)の癌となるソートです。
データ量の多くなった時にshow profileステートメントで、「Creating sort index」の項を確認すれば、相当な時間がかかっていることが確認できると思います。
※データ量が少ないときはインデックスが使われないので「filesort」表示されますが、これは問題ありません。複合インデックスが必要でないか
並び替え列にインデックスが使われていなければ、まずWHERE句等でテーブルに対して先に別のインデックスが使われていないかを確認します。MySQLの場合、1テーブル1インデックスしか使うことができないためです。
先に別のインデックスが使われてしまっている場合、複合インデックスを追加できるかどうか検討しましょう。WHERE句はORDER BY句より先に評価されるので、WHERE句の列, ORDER BY句の列の順番で定義します。複合インデックスで並び替えるSELECT * FROM t1 LEFT JOIN t2 ON t1.t2_id = t2.id WHERE t1.type = 1 ORDER BY t1.日付 DESC /* t1.type単体のインデックスが存在する場合、t1.日付のインデックスはNG t1.type, t2.日付の複合インデックスならOK */ORDER BYは駆動表の列で指定されているか
他に使われるインデックスがない状態でORDER BY句のインデックスが使われていなければ、その並び替え列が駆動表の列で行われているかどうかを確認します。駆動表は、LEFT JOINであれば先に指定したテーブルです。
結合しているクエリで並び替え列を、駆動表の列でなく、内部表の列で指定すると、インデックスを定義していても並び替えに使われず、explainのExtra欄に「filesort, using temporary」と表示されてしまいます。JOIN先のテーブル(内部表)で並び替えはNGSELECT * FROM t1 LEFT JOIN t2 ON t1.t2_id = t2.id ORDER BY t2.日付 DESCJOINは駆動表が親ループの集合となるので、並び替えされたインデックスフェッチで親ループの集合が作成できると、並び替えの必要がなくなりますが、内部表のインデックスフェッチでは、そこで並び替えは完了できません。結合が終わってから改めて並び替え(一時テーブルを作成してクイックソート)する必要があります。
以下の疑似コードで説明します。ネステッドループ結合の疑似コード/* 駆動表の作成にORDER BY句のインデックスを参照できると、そこで並び替え完了 */ t1 = indexFetch(t1, "日付") for each row1 in t1.filter(it => { return it.col == joinKey } { /* 内部表の作成でORDER BY句のインデックスを参照しても、全体の並び替えはできない t2 = indexFetch(t2, "日付") */ for each row2 in t2.filter(it => { return it.col == joinKey } { sendClient(row1, row2) } }SQLでの評価順では、ORDER BY句はJOIN句よりも後ですが、ORDER BY句の定義であってもそのインデックスが使える場合はインデックスフェッチにより、「先に並び替え」が実行されるというのがポイントかと思います。
全件の処理ではなく、インデックスの他に結合条件・検索条件でフェッチできる状況では、
インデックス → 結合 → 検索
の順番で絞り込み処理がされるので、後続の負担が減らせるよう早い段階での絞り込みができれば、より効果的となります。
全体のフェッチにかかった時間は、show profileを実行し、「Sending data」の表示で確認することができます。ちなみに、外部結合ではなく内部結合では、駆動表がオプティマイザの判断次第になるため、駆動表を固定するために、INNER JOINの代わりにSTRAIGHT_JOINを使った方が良いです。
内部結合でもSTRAIGHT_JOINなら、t1は駆動表になることが保証されるSELECT * FROM t1 STRAIGHT_JOIN t2 ON t1.t2_id = t2.id ORDER BY t1.日付 DESCそれでは、どうしても内部表の列で並び替えする必要がある場合はどうすれば良いでしょうか。
その場合は、対処療法になりますがサブクエリで、先に内部表にあたるテーブルの並び替えを済ませ、合わせてLIMITを行うことが考えられます。その結果と、元の内部表を結合します。並び替えとLIMITをサブクエリで行うパターンSELECT * FROM t1 LEFT JOIN ( ( SELECT * FROM t2 ORDER BY 日付 DESC LIMIT 0, 20 ) as sorted_t2 INNER JOIN t2 ON sorted_t2.id = t2.id ) as tmp_t2 ON t1.t2_id = t2.idtmp_t2はサブクエリの結果による一時テーブルのため、t1との結合にインデックスを使うことはできなくなりますが、並び替えとそこからの頭読み出しが完了し、件数が少なくなっているため、問題ではなくなります。
ただ、ページング用のLIMITを自前で指定する必要があるので、WebアプリケーションのORMによるSQL構築は適さなくなります。GROUP BYにインデックスを使えているか
GROUP BYによっても、暗黙的にソートが発生します。サブクエリで集計の一時テーブルを作り、駆動表と結合しているケースを例にすると、一時テーブル内でGROUP BYするカラムのインデックスを作成して、ソートを防ぐことができます。
駆動表と一時テーブルとの結合条件にインデックスは使えないため、GROUP BY時のインデックスフェッチは使いたいところですが、もし何らかの理由でインデックス再設計を避けたい場合は、ORDER BY NULL指定をすることで、GROUP BYによる暗黙ソートを止めることできます。(MySQL8.0ではこの暗黙ソートが無くなるとのことです)SELECT * FROM t1 LEFT JOIN ( /* t2にadd indexしたくない時、並び替えを防ぐ */ SELECT * FROM t2 GROUP BY 日付 ORDER BY NULL ) as grouping_t2 ON sorted_t2.id = t2.id今回は件数の多いデータを処理するために、まずソート処理の問題解決を図ることが効果的であることを書きました。
ちょうどSQLチューニングネタで記事を書きたいと思っていたところに、こちらの素晴らしい記事に触発されました。。
ソート以外にも書くつもりでしたが、まとまらなかったので、一旦打ち切ることにします。
また機会があれば書いてみたいと思います。参考文献
http://nippondanji.blogspot.com/2009/03/using-filesort.html
https://www.slideshare.net/yoku0825/whereorder-by
- 投稿日:2020-01-12T08:36:16+09:00
Order Byを制してWebアプリの一覧表示を速くする
対象読者
- Webアプリケーションエンジニア
- SQLチューニングの基本を学習ずみ
使用環境
- MySQL 5.6
一覧表示の抱えるリスク
webアプリケーションにおけるデータの一覧表示処理は、SQLが遅くなる可能性の高い処理です。
時間が経つとともにデータが増え、複数のテーブル結合で走査件数が多くなりやすいことに加え、大抵の場合、ソート機能を備えているからです。
このソート処理は、走査件数が多くなるほどにコストが非常に高まってくる問題児です。
この記事ではそんなソート処理への対策について、自分自身の理解を深めるためにも内容をまとめてみたいと思います。大規模のデータの全件を処理するとコストが高いので、ページングなどでLIMIT句をつけると良いと考えても、LIMIT句が適用されるのはSQL評価順序の最後なので、その前に処理時間のかかる箇所があると改善されません。
遅い箇所を調べていくのですが、SQLがORDER BYしているならば、まずはORDER BY句の列にインデックスが定義され、それが使えているかどうかをチェックするのが良いと思います。インデックスとソートの関係について
インデックスは並び替えられた状態でデータを持っているため、Order By句に指定した列のインデックスからデータをフェッチできている場合は、その時点でソートは完了します。
しかし、そうでない場合は、毎回メモリ内でソート(クイックソート)を行うので、データ量が多くなったとき、大変遅くなってしまいます。
そのため、ソート列にインデックスを定義することと、それが使用されるようにすることが対処の要点になります。悪玉ソート処理の確認
explainステートメントを発行したとき、key欄に並び替え列のインデックスの表示がなく、Extra欄に「filesort」表示があるなら、インデックスが使用されずにDBサーバのメモリ内でソートされています。これは年老いてから(レコードが増えてから)の癌となるソートです。
データ量の多くなった時にshow profileステートメントで、「Creating sort index」の項を確認すれば、相当な時間がかかっていることが確認できると思います。
※データ量が少ないときはインデックスが使われないので「filesort」表示されますが、これは問題ありません。複合インデックスが必要でないか
並び替え列にインデックスが使われていなければ、まずWHERE句等でテーブルに対して先に別のインデックスが使われていないかを確認します。MySQLの場合、1テーブル1インデックスしか使うことができないためです。
先に別のインデックスが使われてしまっている場合、複合インデックスを追加できるかどうか検討しましょう。WHERE句はORDER BY句より先に評価されるので、WHERE句の列, ORDER BY句の列の順番で定義します。複合インデックスで並び替えるSELECT * FROM t1 LEFT JOIN t2 ON t1.t2_id = t2.id WHERE t1.type = 1 ORDER BY t1.日付 DESC /* t1.type単体のインデックスが存在する場合、t1.日付のインデックスはNG t1.type, t2.日付の複合インデックスならOK */ORDER BYは駆動表の列で指定されているか
他に使われるインデックスがない状態でORDER BY句のインデックスが使われていなければ、その並び替え列が駆動表の列で行われているかどうかを確認します。駆動表は、LEFT JOINであれば先に指定したテーブルです。
結合しているクエリで並び替え列を、駆動表の列でなく、内部表の列で指定すると、インデックスを定義していても並び替えに使われず、explainのExtra欄に「filesort, using temporary」と表示されてしまいます。JOIN先のテーブル(内部表)で並び替えはNGSELECT * FROM t1 LEFT JOIN t2 ON t1.t2_id = t2.id ORDER BY t2.日付 DESCJOINは駆動表が親ループの集合となるので、並び替えされたインデックスフェッチで親ループの集合が作成できると、並び替えの必要がなくなりますが、内部表のインデックスフェッチでは、そこで並び替えは完了できません。結合が終わってから改めて並び替え(一時テーブルを作成してクイックソート)する必要があります。
以下の疑似コードで説明します。ネステッドループ結合の疑似コード/* 駆動表の作成にORDER BY句のインデックスを参照できると、そこで並び替え完了 */ t1 = indexFetch(t1, "日付") for each row1 in t1.filter(it => { return it.col == joinKey } { /* 内部表の作成でORDER BY句のインデックスを参照しても、全体の並び替えはできない t2 = indexFetch(t2, "日付") */ for each row2 in t2.filter(it => { return it.col == joinKey } { sendClient(row1, row2) } }SQLでの評価順では、ORDER BY句はJOIN句よりも後ですが、ORDER BY句の定義であってもそのインデックスが使える場合はインデックスフェッチにより、「先に並び替え」が実行されるというのがポイントかと思います。
全件の処理ではなく、インデックスの他に結合条件・検索条件でフェッチできる状況では、
インデックス → 結合 → 検索
の順番で絞り込み処理がされるので、後続の負担が減らせるよう早い段階での絞り込みができれば、より効果的となります。
全体のフェッチにかかった時間は、show profileを実行し、「Sending data」の表示で確認することができます。ちなみに、外部結合ではなく内部結合では、駆動表がオプティマイザの判断次第になるため、駆動表を固定するために、INNER JOINの代わりにSTRAIGHT_JOINを使った方が良いです。
内部結合でもSTRAIGHT_JOINなら、t1は駆動表になることが保証されるSELECT * FROM t1 STRAIGHT_JOIN t2 ON t1.t2_id = t2.id ORDER BY t1.日付 DESCそれでは、どうしても内部表の列で並び替えする必要がある場合はどうすれば良いでしょうか。
その場合は、対処療法になりますがサブクエリで、先に内部表にあたるテーブルの並び替えを済ませ、合わせてLIMITを行うことが考えられます。その結果と、元の内部表を結合します。並び替えとLIMITをサブクエリで行うパターンSELECT * FROM t1 LEFT JOIN ( ( SELECT * FROM t2 ORDER BY 日付 DESC LIMIT 0, 20 ) as sorted_t2 INNER JOIN t2 ON sorted_t2.id = t2.id ) as tmp_t2 ON t1.t2_id = t2.idtmp_t2はサブクエリの結果による一時テーブルのため、t1との結合にインデックスを使うことはできなくなりますが、並び替えとそこからの頭読み出しが完了し、件数が少なくなっているため、問題ではなくなります。
ただ、ページング用のLIMITを自前で指定する必要があるので、WebアプリケーションのORMによるSQL構築は適さなくなります。GROUP BYにインデックスを使えているか
GROUP BYによっても、暗黙的にソートが発生します。サブクエリで集計の一時テーブルを作り、駆動表と結合しているケースを例にすると、一時テーブル内でGROUP BYするカラムのインデックスを作成して、ソートを防ぐことができます。
駆動表と一時テーブルとの結合条件にインデックスは使えないため、GROUP BY時のインデックスフェッチは使いたいところですが、もし何らかの理由でインデックス再設計を避けたい場合は、ORDER BY NULL指定をすることで、GROUP BYによる暗黙ソートを止めることできます。(MySQL8.0ではこの暗黙ソートが無くなるとのことです)SELECT * FROM t1 LEFT JOIN ( /* t2にadd indexしたくない時、並び替えを防ぐ */ SELECT * FROM t2 GROUP BY 日付 ORDER BY NULL ) as grouping_t2 ON sorted_t2.id = t2.id今回は件数の多いデータを処理するために、まずソート処理の問題解決を図ることが効果的であることを書きました。
ちょうどSQLチューニングネタで記事を書きたいと思っていたところに、こちらの素晴らしい記事に触発されました。。
ソート以外にも書くつもりでしたが、まとまらなかったので、一旦打ち切ることにします。
また機会があれば書いてみたいと思います。参考文献
http://nippondanji.blogspot.com/2009/03/using-filesort.html
https://www.slideshare.net/yoku0825/whereorder-by
- 投稿日:2020-01-12T06:24:52+09:00
ドットインストール mysql>の状態(=mysqlサーバーに接続されている状態)にする為の手順・作業終了後、安全に終了する為の手順【完全版】
①Spotlight検索よりターミナルを起動
②$ cd(フォルダに移動)
③$ cd MyVagrant(仮想マシンをまとめたフォルダに移動)
④$ cd myCentOS(仮想マシンのフォルダに移動)
⑤$ vagrant up(仮想マシンが起動する)※30秒ほどかかる
⑥$ vagrant ssh(仮想マシンにログインする)※5秒ほどかかる
⑦[vagrant@localhost 〜]$ となっているのを確認(ログインできている証拠)
⑧Spotlight検索から、cyberduckを立ち上げる(ファイル転送ツールを立ち上げる)
⑨ブックマークを設定している為、出てきたもの(MyCentOS)をダブルクリック(仮想マシンにアクセスする)
※このブックマークの設定は、ローカル開発環境の構築[macOS編]#09 仮想マシンにアクセスしてみよう でやります。⑩/home/vagrantに移動できているかを確認する
※移動出来ていなければ、▲マークの左側のボタンを押して、→/home/vagrantを選択する11.mysql_lessonsのフォルダをダブルクリック_
※既に作成済み12.ターミナルに戻る
13.$ cd mysql_lessons(作成済みのmysql_lessonsのフォルダに、ターミナル上で移動する)
14.[vagrant@localhost mysql_lessons]$ となっているか確認する_
15.$ pwd(ターミナル上での現在の場所を確認する為に使う)
16./home/vagrant/mysql_lessons_
[vagrant@localhost mysql_lessons]$_ となっていることを確認する
(これは、cyberduckで作成済みのmysqlフォルダでの作業中ということ)17.$ sudo service mysqld status
(管理者コマンドを使って、mysqlサーバーが動いているかどうか調べる)18.〜を実行中と出ていればOK(これでmysqlサーバーに接続する準備が整う)
※ローカル開発環境下では、バックグラウンドで、既にmysqlサーバーが動いている状態。19.$ mysql -u root(これでmysqlサーバーに接続される)
20.mysql>となっていることを確認する
※mysql>となっていれば、mysqlサーバーに接続されている状態。※ターミナル上に、Sever version:5.6.46 MySQL〜と記載があれば、
MySQLの5.6を使う、という感じです。補足1:control+Lで画面をスッキリできる
($ clearとした時と同じ状態。但し、今はコマンドプロンプトが「$」ではなく、「>」の為、$ clearは使えない。)
https://bit.ly/2QBwBOk
の記事の補足1:プロンプトとはを参照。作業
作業終了後、安全に修了する為の手順
①mysql>の状態であることを確認する
②mysql> quit; もしくは mysql> \q(これでサーバーの接続が終了する)
③Bye
[vagrant@localhost mysql_lessons]$ となるのを確認する_④$ exit(これで仮想マシンからログアウトできて、mbpの操作に戻る)
※mbpはMacBook Proのこと。⑤$ vagrant suspend(これで仮想マシンを停止できる)※5秒ほどかかる。
⑥$ exit(これでターミナルを終了できる)
※自分はここまでやるとターミナルを自動的に閉じる設定にしています。詳しくは、ローカル開発環境の構築の#11 学習をやめる手順を見ていこう の1:00〜辺りをご覧ください。⑦cyberduckを×で消す
⑧終わり
- 投稿日:2020-01-12T04:19:44+09:00
MySQLの照合順序について
はじめに
テーブルを作るときに照合順序の指定を間違えて、期待したことができず混乱したのでメモ。
経緯
mysqlテーブルを使って一種のバージョン管理を行うため、比較条件の厳しいutf8_binを使おうとしたら照合順序がテーブルに反映されなかった。
期待する結果
テーブルを作成する時、データベースに設定された照合順序に合わせて文字コードなどが指定されること。
SQL文を色々試してみた。
正しいSQL文
文字コードと照合順序を正しく指定したSQL文を処理させてみる。
正しいSQL文create `database name`.`table name` ( column_name data_type ( number ) column_name data_type ( number ) ) character set utf8 collate utf8-bin;結果、文字コードと照合順序を正しく指定しているため、想定通りのテーブルとなる。
文字コードだけ指定したSQL文
文字コードは正しく指定するが、照合順序を指定していないSQL文を処理させてみる。
指定された文字コードをもとにinformation_schema.character_setに対応したis_default=yesの照合順序から取ってくるcreate `database name`.`table name` ( column_name data_type ( number ) column_name data_type ( number ) ) charset set utf8;結果、作成されるテーブルの照合順序は思い通りになるとは限らない。
文字コードも照合順序も省いたSQL文
文字コードと照合順序を指定しないSQL文を処理させてみる。
データベースに設定されている文字コードと照合順序を持ってくるcreate `database name`.`table name` ( column_name data_type ( number ) column_name data_type ( number ) );結論
当たり前のことだけど、SQL文をテキトーに書くと思った挙動にならないので注意が必要。
参考