QKAKE::TECH

テックなことを書く

【MySQL】Using filesort について調べた

Using filesort とは

  • MySQL のクエリの実行計画をみたときに、Extra 列に Using filesort; と表示されること。
  • インデックスを利用しないクイックソートが用いられていることを示している。

なにが問題か

  • Using filesortはインデックスを利用しないクイックソートにより速度が低下する。
    • filesort が何ソートなのかは以下が詳しい。

blog.shibayu36.org

いつ発生するのか

  • ORDER BY 句があるときに適切なインデックスがないと Using filesort が出る。
  • ソートに必要なメモリが sort_buffer_size より大きくなったとき。
    • テンポラリファイルが作られ、メモリとファイルを併用してクイックソートが実行される。
    • ちゃんとインデックスが利用されるようにして、インデックス順で行をフェッチできるようにすれば filesort は不要である。

どう解決するか

mysql>EXPLAIN SELECT name, type, from users WHERE type = 3; 

上記でクエリの実行計画をみて、適切にインデックスが貼られているか確認する。複数のカラムにまたがるクエリの場合、複合インデックスを追加するなどする。

mysql>EXPLAIN SELECT name, type, from users WHERE type = 3 \G 

末尾に \G をつけると結果が縦に表示されてみやすくなるっぽい。

refs

【Ruby】連想配列(ハッシュ)の値を複数個設定したいとき

pry(main)> users = Hash.new
=> {}
pry(main)> users[:male]
=> nil
pry(main)> users[:male] = "Yuji"
=> "Yuji"
pry(main)> users[:male]
=> "Yuji"
pry(main)> users
=> {:male=>"Yuji"}

ユーザの名前を管理する連想配列(ハッシュ)をつくり、 male という key で "Yuji" という値を代入したらこうなる。 次に同じ key の male"Taro" を代入すると次のようになる。

pry(main)> users[:male] = "Taro"
=> "Taro"
pry(main)> users
=> {:male=>"Taro"}

あたらしく別のオブジェクトとして {:male=>"Taro"} という連想配列が出来上がっている。 このように連想配列はひとつの key に対してひとつの value を取るような機構になっている。

そこで、ひとつの key に対して複数の value を持ちたい場合は value を配列でとるといい。

pry(main)> users[:male] = ["Yuji", "Taro"]
=> ["Yuji", "Taro"]                  
pry(main)> users
=> {:male=>["Yuji", "Taro"]}
pry(main)> users[:male].each {|user| puts user}
Yuji                                 
Taro              
=> ["Yuji", "Taro"]

そうすることで users[:male]Array#each で回すことなどもできるようになる。

ブロックを用いてデフォルト値を設定する

pry(main)> users = Hash.new { |h, k| h[k] = [] }                                                                                                                          
=> {}             
pry(main)> users[:male]           
=> []

Hash.new のときにブロックを渡すと、対応する値がまだ無いキーが呼び出される度に式が評価される。 したがって、上のようにまだ存在しない :male というキーで値を取ろうとしたときに配列が返ってきている。

これを使えばキーが存在する・しないにかかわらず、 Array#<< を用いて次のように値を追加していける。

pry(main)> users[:male] << "Yuji"
=> ["Yuji"]                     
pry(main)> users[:male] << "Taro"                                                                                                                                 
=> ["Yuji", "Taro"]                   
pry(main)> users[:male] << "Ryo"                                                                                                                          
=> ["Yuji", "Taro", "Ryo"]      
pry(main)> users                
=> {:male=>["Yuji", "Taro", "Ryo"]}

同様に女性も追加するなら

pry(main)> users[:female]
=> []
pry(main)> users[:female] << "Saori"
=> ["Saori"]
pry(main)> users[:female] << "Aiko"                                                                                                
=> ["Saori", "Aiko"]

こんな感じ。 ハッシュの中身を見てみると...

pry(main)> users
=> {:male=>["Yuji", "Taro", "Ryo"], :female=>["Saori", "Aiko"]}

といったように male と female で分類しながら、値に複数の名前をとるような構造ができあがっている。

女性の名前を取り出したいときは key を指定しながら each 処理するなどして次のようにかける。

pry(main)> users[:female].each { |user| puts "#{user} さんは女性です" }                                                            
Saori さんは女性です
Aiko さんは女性です
=> ["Saori", "Aiko"]

refs:

【Ruby】複数行の文字列を書くときに改行なしで改行する

str = "本日は
雨天なり"

p str
workspace ➤ ruby string.rb
"本日は\n雨天なり"

このように文字列リテラルの中で改行すると \n が含まれる。

複数行にわたって書くこともできます。 この場合含まれる改行文字は常に\nになります。

リテラル (Ruby 2.3.0)

したがって、 \n を含まずに改行したいときは以下のようにバックスラッシュ記法を用いる。

str = "本日は\
雨天なり"

p str
workspace ➤ ruby string.rb
"本日は雨天なり"

このように文字列をダブルクォートで囲った場合はバックスラッシュ記法が使えるので、\改行 によって改行とはみなされずに改行することができる。 ただしこれはダブルクォートで囲まれているときのみであり、シングルクォートで囲まれているときはこの限りではない。

str = '本日は\
雨天なり'

p str
workspace ➤ ruby string.rb
"本日は\\\n雨天なり"

シングルクォートで囲まれた文字列では行末の \ は \ そのものとして解釈されます。

refs:

ja.stackoverflow.com