ぶろぐ

日記です

充電式インパクトレンチ買った、ついに。

ヤフオクでスクーター安いな買っちゃおう!と思ったらいろいろボロくて・・・。
エンジンかけるとカタカタ音がして、おそらくプーリーなので一度開けてみようかと。このために専用工具を買うのもなんかあれですし、ここはずっと欲しかったインパクトレンチ買ってそれで開けることにしました。
ついでにいろいろネジ外すのもめんどくさいので、こいつで楽をしようかなと。レバーは無段階で調整可能ですので、器用に使えばねじ山潰すこともないかな(要注意)ドリルとしても使えるし。

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)

Golangやるよ!

Golangをやることになったので本を買った。

前書きを見てみると、以下のようなことが。

他の言語を翻訳したようなプログラムを書くのではなく、そもそも実現したかったことをGo言語のやり方に沿って書くようにすれば、元とかなり違ったすっきりとしたプログラムを書くことができます。そのためには、Go言語の慣用表現をマスターすることが必須です。

なるほど、GoにはいればGoに従え・・・。

個人的にはGolangミドルウェア的なシンプルなソフトウェアを作るのに向いていて、ある程度複雑な仕様を持つアプリケーションを書くならScalaとか表現力の高い言語を使った方がいんじゃないかなー感はあるんですがまあやってみよ。
食わず嫌いなのかもしれないし。仰々しいものを作ってしまわず、シンプルなものが出来上がって幸せになるかもしんない。

Golangのネガティブ意見(?)はこちら。

postd.cc

Scalaなら多分全部できる!?

Sumally Pocket 使ってみる

衣替えの時期にやれって感じだけど…使いたくなってしまったのでしょうがない。
いらないの捨てればいい感あるけど…色紙とか捨てられないもらったプレゼント的なやつとか捨てられないし。
あとはシーズンオフで利用しないものとか?
衣替えで着なくなった服とか、スノボのシーズンが終わったらブーツとウェアとかを預ければいいかな。
要らないデスクトップPCとかHHKBのLite2 for Macとかは…誰かもらうかな。地味にCiscoのスイッチとNetscreenが邪魔。何年も読んでない技術書も…。

(´・ω・`)

定時で帰ると酒を飲んだあとにも時間がある。すごい。

長文書こうと思ったけどやめた。

細かすぎて伝わらないようで最高な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を使ってみる利点はあるなーと思う。単純にシンプルになるから。