クエリを考える際の範囲条件と複数等価条件の違い
こんにちは,coreです
indexを使って,テーブルの最適化を行なっているのですが
どうもEXPLAIN結果を見て,「using index」と出ていると
それだけで満足してしまいます_(┐「ε:)_
それではよくない!
ということで,曖昧になりがちな複合インデックスについて.
エントリーのタイトル,自分でもどうつけようか迷ったんですが
とりあえず詰まったので勉強しながら書いていきます…
今回の場面設定
- テーブルの最適化
- SELECTで範囲検索を行いたい
- explainの結果から分からない状況
- テーブル定義は次の通り
createdb user_data(
user_id int unsigned
age int unsigned #20-80歳
sex varchar(2) #M,F
updatetime int unsigned #unixtime
)type=InnoDB;
で,じゃあ今回は上のテーブルから
20代の女の子,テーブル登録が2013年8月に当てはまる行をSELECTします.
その前に
indexはどうやってはりましょうね
とりあえず,user_idは恐らくユーザ固有のもので
他のテーブルにもuser_idがあって,結びつくはずなので
auto_incrementにしているわけではありませんが
user_idはprimary keyにします
mysql> alter table user_data add primary key(user_id);
それから,セカンダリインデックスについては
今回はSELECT文の,WHERE句以降に
user_id以外の全てのカラムが入ってくるので
複合インデックスになることは大体察しがつきます.
ではどういう順番にインデックスを貼ればいいのでしょうか
コメントアウトにあるように,
実際の想定されるデータ値から考えてみます.
---
age -> 20歳から80歳(つまり60通り)
sex -> 女性か男性(2通り)
updatetime -> unixtime
---
あれ.
えーっと,ageとsexについては値が何通りなのか想像出来ますが
updatetimeについては,決め打ちの値が出せません.
このテーブルに登録されている日時は
「いつが最古で,そしていつまでの値が入っているのか」を
明確化していないからですね.
まぁ,なのでとりあえず
「たくさんある」認識で進めていきます.
複合インデックスはindex i1(A,B,C)としたときに
Aの値をソートし,それにあわせてB,Cをおいた状態でindexが作成されます.
だからそれがごちゃごちゃにならないよう
パターンが少ないものからindexをはっていくと 良いような気がします
mysql> alter table user_data add index i1(sex, age, updatetime);
で SELECT文です.
とりあえず素直に書いてみました.
mysql> SELECT user_id from user_data -> WHERE sex = 'F' -> AND age BETWEEN 20 AND 29 -> AND updatetime BETWEEN 1375282800 AND 1377961199;
ところで
MySQLは,範囲条件が2つある場合
その片方でしか綺麗に取ってくることができません.
なので,少し格好悪いかたちになりますが
ageは全てIN句で指定します.
mysql> SELECT user_id from user_data -> WHERE sex = 'F' -> AND age IN(20,21,22,23,24,25,26,27,28,29) -> AND updatetime BETWEEN 1375282800 AND 1377961199;
先ほどあげたクエリと,このクエリ
EXPLAINでみたときに,type=rangeと表示され
ともに範囲クエリであるように思えます.
ただ前者は,カラムageにおいて「値の範囲」を条件とし
後者は「値の等価」を条件としてます.
範囲条件の場合,MySQLはindexの他の列を考慮しませんが
等価条件の場合,そういった制限がありません.
ついつい忘れがちです.
IN句で書ききれないときは,
テーブル設計を見なおしたり
検索条件そのものの方針が誤っていたり
…っていう可能性が
高いのではないでしょうか.
MySQLにおけるベンチマークのなんたるかを考える必要性に陥った
PerlでPlease check that your locale settingsという警告が出たときの対処
perlでコンパイルしたときに,
perl: warning: Setting locale failed. perl: warning: Please check that your locale settings: LANGUAGE = (unset), LC_ALL = (unset), LANG = "ja_JP.eucJP" are supported and installed on your system. perl: warning: Falling back to the standard locale ("C").
…というエラーが出て来ました.
こまった(●☌◡☌●)
コンパイルは普通に通るのですが,
のちのち何かで困りそうなので対処します.
エラーメッセージにあるように,ロケールの設定がおかしいので
/etc/sysconfig/i18nの中身を次のように変更します.
LANG="ja_JP.UTF-8" LANG="ja_JP.eucJP" SUPPORTED="ja_JP.eucJP:ja_JP:ja"
いったんログインユーザからrootにログアウトし,
再ログインを行えばエラーはでなくなります.
Linuxに管理者権限を持った新規ユーザの作成
※!suではなくsu -でrootユーザにしないと
環境によってはコマンドがnot foundと言われてしまいます!※
以下の例では,作成するユーザ名をcoreにしています(*´ェ`*)
[root@localhost ~]# useradd core useradd: user core exists [root@localhost ~]# passwd core Changing password for user core. New UNIX password: Retype new UNIX password: passwd: all authentication tokens updated successfully.
wheelグループに追加し,sudoできるようにします
[root@localhost ~]# usermod -G wheel core [root@localhost ~]# visudo
以下の行を「/wheel」などのviコマンドで検索し,コメントアウトを外します.
## Same thing without a password %wheel ALL=(ALL) NOPASSWD: ALL
実際に作成したユーザでログインし,適当なコマンドを打って通ったら成功です.
以下の例では日時を出しています.
[root@localhost ~]# su core [core@localhost root]$ sudo date [sudo] password for core: Thu Jun 27 15:21:41 JST 2013
.vimrcの設定をメモしておく
今のところこんなかんじです
set tabstop=4 set number set fileencodings=utf8,iso-2002-jp,cp932,euc-jp set autoindent set shiftwidth=4 set smartindent set cindent "when open the file, show the status. set laststatus=2 set statusline=%F%m%r%h%w\%=[TYPE=%Y]\[FORMAT=%{&ff}]\[ENC=%{&fileencoding}]\[LOW=%l%L] set t_Co=256 "colorscheme desert set nocompatible set whichwrap=b,s,h,l,<,>,[,] set backspace=indent,eol,start syntax on
githubでpush時にrejectされてしまうあれ
gitがうまく使いこなせない
pushすると次のようなメッセージがくる
To https://github.com/0x0core ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'https://github.com/0x0core' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Merge the remote changes (e.g. 'git pull') hint: before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
これとかこれとか試してみたんだけれど
よくわからなくなって結局繰り返し
(´;ω;`)
とりあえずローカルのリポジトリの.gitを削除して
いちからやることに
# git init Initialized empty Git repository in ***/.git/ # git add . # git status # git remote add origin https://github.com/0x0core # git push origin master
…と,ここで上記エラー.
何が違うんだろうか…
fetchrow_hashref()でDBIのvalueだけ取り出したい
件名そのまんまです
未解決なのですが同じ事を何度もやらないように…
環境:OS->CentOS 5.9 / MySQL-> 5.0
【目的】
Perl内でSQL文を実行
その際にSELECTを用いた場合,結果の取得の手法
DBIだしデータ量が膨大なのでfetchrow_hashref()を使う
ほにゃ_(┐「ε:)_
とりあえずプログラムの一部を載せます
my $dbh = DBI->connect($ds,$user,$pass,$option)or die("connection failed."); my $sth= $dbh->prepare("SELECT * FROM table_name ORDER BY columns" ); $sth->execute(); my @file_data; #格納用 while(my $row = $sth->fetchrow_hashref()){ $printer=%$row; push(@file_data,%$row,"---<br>"); } $dbh->disconnect();
テーブルの中からすべてのVALUEを取得したいんだけれど
このままだと(おそらく)ハッシュのKEYまで拾ってきてしまって
情報として整理するときに不便…
フィールド名が何回も登場するんです´v`
なのと,
配列に格納するときに「,」で区切りたいんだけれど
その正規表現をどうやってハッシュに対してやればいいのか
ハッシュとリファレンスの理解の浅さが@ω@
なやむ
未解決〜