joinしているテーブルでUsing temporary; Using filesort が出て遅い時
Railsを触るヽ('ω')ノ三ヽ('ω')ノ
とある日MySQLのチューニングをしていると Using temporary; Using filesort に出会う。
記事テーブルとコメントテーブルをjoinしているようなクエリ。とあるカテゴリの最新のコメント3件がほしい、またコメントしている記事の情報もほしい。
WHERE句で使っている検索条件のテーブルが、2つのテーブルでまたがってしまっている場合、一度JOINした後にSORTなどいろいろやらねばならず無駄である。先にレコードを絞ってからjoinしたほうが効率的。*1
そのため、1つのテーブルに検索条件を寄せて、Using filesortが出ないようにした。
NG case
SELECT `comments`.*, `post`.* FROM `comments` INNER JOIN `posts` ON `posts`.`id` = `comments`.`post_id` WHERE `posts`.`category_id` = 161 -- ☆ここがまずい AND ( comments.status = 1 AND comments.created_at <= '2016-03-27 18:11:47' ) ORDER BY comments.created_at DESC LIMIT 3; +----+-------------+----------+------+-----------------------------+-----------------+---------+--------------------------------+------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+-----------------------------+-----------------+---------+--------------------------------+------+---------------------------------+ | 1 | SIMPLE | posts | ref | PRIMARY,category_id_idx | category_id_idx | 5 | const | 694 | Using temporary; Using filesort | | 1 | SIMPLE | comments | ref | post_id_idx,created_at_idx | post_id_idx | 5 | development.posts.id | 21 | Using where | +----+-------------+----------+------+-----------------------------+-----------------+---------+--------------------------------+------+---------------------------------+ 2 rows in set (0.00 sec)
OK case
SELECT `comments`.*, `post`.* FROM `comments` INNER JOIN `posts` ON `posts`.`id` = `comments`.`post_id` WHERE `comments`.`category_id` = 161 -- ☆ 一度commentsテーブルを絞ってからjoinする AND ( comments.status = 1 AND comments.created_at <= '2016-03-27 18:11:47' ) ORDER BY comments.created_at DESC LIMIT 3; +----+-------------+----------+--------+---------------------------------------------+----------------+---------+----------------------------------------+-------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+--------+---------------------------------------------+----------------+---------+----------------------------------------+-------+-------------+ | 1 | SIMPLE | comments | range | post_id_idx,category_id_idx,created_at_idx | created_at_idx | 6 | NULL | 89540 | Using where | | 1 | SIMPLE | posts | eq_ref | PRIMARY | PRIMARY | 4 | development.comments.post_id | 1 | NULL | +----+-------------+----------+--------+---------------------------------------------+----------------+---------+----------------------------------------+-------+-------------+ 2 rows in set (0.00 sec)
いいね!
*1:JOINせずに、先にcommentsテーブルを取得して、それからpostsテーブルを引く二回に分ける方法もありだと思います。
レーベンシュタイン距離
サジェストで使うアルゴリズム
#!/usr/bin/env python # coding: utf8 import Levenshtein import sys inputString = sys.argv[1].decode('utf-8') strings = [ "大城しゅうじ", "大城ひろし", "大城隆史", "天野かつた", "比嘉太郎", "比嘉まさし", "大城まさし", "辺土名まさし", "オダスキーさん" ] for s in strings: l = Levenshtein.distance(inputString, s.decode('utf-8')) if (l <= 3): print(" 距離: " + str(l) + ", もしかして: " + s)
医療費控除のため確定申告してきた
骨折で手術して医療費が10万超えたので申告。
まあまあ還付あるかなーと思ったが、結果1300円程度の還付。
あれ…?交通費と時間考えたらあまりやる意味なかった!!
Golangやるよ!
Golangをやることになったので本を買った。
前書きを見てみると、以下のようなことが。
他の言語を翻訳したようなプログラムを書くのではなく、そもそも実現したかったことをGo言語のやり方に沿って書くようにすれば、元とかなり違ったすっきりとしたプログラムを書くことができます。そのためには、Go言語の慣用表現をマスターすることが必須です。
なるほど、GoにはいればGoに従え・・・。
個人的にはGolangはミドルウェア的なシンプルなソフトウェアを作るのに向いていて、ある程度複雑な仕様を持つアプリケーションを書くならScalaとか表現力の高い言語を使った方がいんじゃないかなー感はあるんですがまあやってみよ。
食わず嫌いなのかもしれないし。仰々しいものを作ってしまわず、シンプルなものが出来上がって幸せになるかもしんない。
Golangのネガティブ意見(?)はこちら。
Scalaなら多分全部できる!?
(´・ω・`)
定時で帰ると酒を飲んだあとにも時間がある。すごい。
長文書こうと思ったけどやめた。
細かすぎて伝わらないようで最高なtips。今日使ったscalazのメソッドを書く。
安全にmimByやmaxBy、あるいはtoIntを行う
case class HogeClass(id: Int, size: Int) val hs = List(Hoge(1,1), Hoge(2,2,), Hoge(3,3) hs.minBy(_.size) // Hoge(1,1) hs.maxBy(_.size) // Hoge(3,3) // 普通。でもListがemptyだとエラーに。 List().minBy(_.size) // エラー // モナディックな我々としては安全に操作したい所。TryやEitherで囲んでもいいけど冗長な記述がカッコ悪い。 // ラップした関数を作りたくなる。しかし、ScalazにはminimuByがある。 // これはOptionにくるんで返してくれる。 hs.minimumBy(_.size) // Option(Hoge(1,1)) List().minimumBy(_.size) // None // toIntも、parseIntがそれっぽく。 "1".toInt // 1 "hoge".toInt // エラー "hoge".parseInt.toOption // None "1".parseInt.toOption // Some(1)
ムズカシイ思想までいかず、Optionに魅力を感じているレベルでもScalazを使ってみる利点はあるなーと思う。単純にシンプルになるから。