SlideShare une entreprise Scribd logo
1  sur  133
Ruby on Rails
on MySQL
チューニング入門

佐藤大資 (@eccyan)
Ruby on Rails を使えば簡単に誰でも
Web サービスを構築する事が出来ます。
Ruby on Rails を使えば簡単に誰でも
Web サービスを構築する事が出来ます。
しかし、SQLを理解せずに
Active Record を利用していると・・・
そこで今回は、
そこで今回は、
そこで今回は、
そこで今回は、

に絞ってチューニングの
取り掛り方法をお伝えします。
ActiveRecordって何?

ActiveRecord って何?
ActiveRecordって何?

ActiveRecord って何?
• DBテーブルの1行が1つのクラス
ActiveRecordって何?

ActiveRecord って何?
• DBテーブルの1行が1つのクラス
• 色々なRDBMSを同じソースコードで
(MySQL, PostgreSQL, SQLite,
SQL Server, Sybase, and Oracle)
ActiveRecordって何?

ActiveRecord って何?
• DBテーブルの1行が1つのクラス
• 色々なRDBMSを同じソースコードで
(MySQL, PostgreSQL, SQLite,
SQL Server, Sybase, and Oracle)
• SQL再利用の仕組みがある
ActiveRecordって何?

ストアドプロシージャ?
DELIMITER //
DROP PROCEDURE IF EXISTS proc1//
CREATE PROCEDURE proc1()
BEGIN
SELECT VERSION();
END;
//
DELIMITER ;
ActiveRecordって何?

ストアドプロシージャ?
DELIMITER //
DROP PROCEDURE IF EXISTS proc1//
CREATE PROCEDURE proc1()
BEGIN
SELECT VERSION();
END;
//
DELIMITER ;
ActiveRecordって何?

ストアドプロシージャ?
• 処理速度は早いが、負荷集中する
• Master-Slave 構成の場合、更新系の
負荷分散が出来ない
• RDBMS毎に構文やノウハウが変わる
ActiveRecordって何?
/**
* ページングクエリ(LIMIT 付き) を実行する
*
* 注: $sql は SELECT で始めてください。
* $sql に SELECT SQL_CALC_FOUND_ROWS を入れないでください。
*
* ページングパラメータ($paging) について
* <pre>
* page
ページ番号(1-) empty や 0 以下の場合は 1 が仮定される
* pagesize
ページサイズ empty や 0 以下の場合は最後まで
* no_count
true: カウント不要, empty: カウント必要
* </pre>
*
* @param stdclass $db
DB ハンドラ
* @param string $sql
SQL
* @param string $params パラメータ
* @param array $paging ページングパラメータ
* @param string $key
null: 結果は array of array
*
$key を指定すると結果をある列の配列で返す
* @return array
array('total' => 全件数, 'list' => 結果)
*
ただし、 $pageing['no_count'] が true の場合は
*
結果のみを返します。
*/
public function doPagingQuery($db, $sql, $params, $paging, $key = null)
{
if (empty($paging['no_count'])) {
$sql = preg_replace('/SELECT/i',
'SELECT SQL_CALC_FOUND_ROWS', $sql, 1);
}

オレオレライブラリ?

// ページング条件
$this->createLimitClause($limitClause, $params, $paging);
$sql .= ' ' . $limitClause;
// 実行
$list = $db->query($sql, $params)->result_array();
if ($key) {
foreach ($list as &$value) {
$value = $value[$key];
}
}
if (empty($paging['no_count'])) {
// 全件数を取得する
$totalResult = $db->query('SELECT FOUND_ROWS() AS total')
->row_array();
$total = $totalResult['total'];
}
ActiveRecordって何?
/**
* ページングクエリ(LIMIT 付き) を実行する
*
* 注: $sql は SELECT で始めてください。
* $sql に SELECT SQL_CALC_FOUND_ROWS を入れないでください。
*
* ページングパラメータ($paging) について
* <pre>
* page
ページ番号(1-) empty や 0 以下の場合は 1 が仮定される
* pagesize
ページサイズ empty や 0 以下の場合は最後まで
* no_count
true: カウント不要, empty: カウント必要
* </pre>
*
* @param stdclass $db
DB ハンドラ
* @param string $sql
SQL
* @param string $params パラメータ
* @param array $paging ページングパラメータ
* @param string $key
null: 結果は array of array
*
$key を指定すると結果をある列の配列で返す
* @return array
array('total' => 全件数, 'list' => 結果)
*
ただし、 $pageing['no_count'] が true の場合は
*
結果のみを返します。
*/
public function doPagingQuery($db, $sql, $params, $paging, $key = null)
{
if (empty($paging['no_count'])) {
$sql = preg_replace('/SELECT/i',
'SELECT SQL_CALC_FOUND_ROWS', $sql, 1);
}

オレオレライブラリ?

// ページング条件
$this->createLimitClause($limitClause, $params, $paging);
$sql .= ' ' . $limitClause;
// 実行
$list = $db->query($sql, $params)->result_array();
if ($key) {
foreach ($list as &$value) {
$value = $value[$key];
}
}
if (empty($paging['no_count'])) {
// 全件数を取得する
$totalResult = $db->query('SELECT FOUND_ROWS() AS total')
->row_array();
$total = $totalResult['total'];
}
ActiveRecordって何?

オレオレライブラリ?
• 属人性が高い
• OSSに比べて枯れていない
• プラグマブルで無く、代替出来ない
ActiveRecordって何?

ARで再利用可能なコードを書こう
• Arel
• Relation
• Scope
ActiveRecordって何?

Scope
scope :active, where(active: true)
scope :inactive, where(active: false)
ActiveRecordって何?

Scope
scope :active, where(active: true)
scope :inactive, where(active: false)
scope :adult_categories, lambda {
# 大人向けカテゴリのIDは 1, 5, 6
active.where(category_id: [1, 5, 6])
}
負荷の少ないクエリとは?

負荷の少ないクエリとは?
負荷の少ないクエリとは?

負荷の少ないクエリとは?
• 検索処理が軽い
負荷の少ないクエリとは?

負荷の少ないクエリとは?
• 検索処理が軽い
• 並び替え処理が軽い
負荷の少ないクエリとは?

負荷の少ないクエリとは?
• 検索処理が軽い
• 並び替え処理が軽い
• 結合処理が軽い
負荷の少ないクエリとは?

負荷の少ないクエリとは?
• 検索処理が軽い
• 並び替え処理が軽い
• 結合処理が軽い
EXPLAIN で調べよう
負荷の少ないクエリとは?

EXPLAIN
• インデックスが必要か確認できる
• 結合順序が最適か確認できる
負荷の少ないクエリとは?

EXPLAIN
mysql> EXPLAIN SELECT `answers`.`id` AS t0_r0, `answers`.`old_id` AS t0_r1, `answers`.`question_id` AS t0_r2,
`answers`.`user_id` AS t0_r3, `answers`.`question_user_id` AS t0_r4, `answers`.`to_user_id` AS t0_r5,
`answers`.`parent_id` AS t0_r6, `answers`.`content` AS t0_r7, `answers`.`ng_word` AS t0_r8, `answers`.`check` AS
t0_r9, `answers`.`active` AS t0_r10, `answers`.`created_at` AS t0_r11, `answers`.`updated_at` AS t0_r12,
`questions`.`id` AS t1_r0, `questions`.`old_id` AS t1_r1, `questions`.`old_random_key` AS t1_r2,
`questions`.`parent_category_id` AS t1_r3, `questions`.`category_id` AS t1_r4, `questions`.`user_id` AS t1_r5,
`questions`.`to_user_id` AS t1_r6, `questions`.`type_id` AS t1_r7, `questions`.`is_serious` AS t1_r8,
`questions`.`content` AS t1_r9, `questions`.`ng_word` AS t1_r10, `questions`.`display` AS t1_r11, `questions`.`check`
AS t1_r12, `questions`.`access_count` AS t1_r13, `questions`.`use_image` AS t1_r14, `questions`.`image_url` AS
t1_r15, `questions`.`link_url` AS t1_r16, `questions`.`active` AS t1_r17, `questions`.`answer_last_updated_at` AS
t1_r18, `questions`.`created_at` AS t1_r19, `questions`.`updated_at` AS t1_r20, `questions`.`last_answer_id` AS t1_r21
FROM `answers` INNER JOIN `users` ON `users`.`id` = `answers`.`user_id` INNER JOIN `questions` ON
`questions`.`id` = `answers`.`question_id` WHERE `answers`.`active` = 1 AND (answers.user_id = 1) AND
(answers.question_user_id != 1) AND (answers.to_user_id = 1 OR answers.to_user_id is NULL) AND
(questions.active = 1) AND (questions.id IN ( SELECT temp_a.question_id FROM answers as temp_a WHERE
temp_a.user_id = 1 )) AND (answers.ng_word IN (0, 1)) GROUP BY answers.question_id ORDER BY
questions.answer_last_updated_at desc;
負荷の少ないクエリとは?

EXPLAIN
+----+--------------------+-----------+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------+---------+------------------------------------+------+----------------------------------------------+
| id | select_type
| table | type
| possible_keys
| key
| key_len | ref
| rows | Extra
|
+----+--------------------+-----------+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------+---------+------------------------------------+------+----------------------------------------------+
| 1 | PRIMARY
| users | const
| PRIMARY
| PRIMARY
|4
| const
| 1 | Using index; Using temporary; Using filesort |
| 1 | PRIMARY
| answers | ref
|
index_answers_on_question_id_and_user_id_and_created_at,index_answers_on_question_id_and_created_at,index_answers_on_user_id_and_created_at,index_answers_on_
to_user_id_and_created_at,index_answers_on_question_user_id_and_created_at | index_answers_on_user_id_and_created_at
|4
| const
| 196
| Using where
|
| 1 | PRIMARY
| questions | eq_ref
| PRIMARY,index_questions_on_id
| PRIMARY
|4
| rio_production.answers.question_id | 1 | Using where
|
| 2 | DEPENDENT SUBQUERY | temp_a | index_subquery |
index_answers_on_question_id_and_user_id_and_created_at,index_answers_on_question_id_and_created_at,index_answers_on_user_id_and_created_at
| index_answers_on_question_id_and_user_id_and_created_at | 8
| func,const
| 4 | Using index; Using where
|
+----+--------------------+-----------+----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------+---------+------------------------------------+------+----------------------------------------------+
4 rows in set (0.01 sec)
負荷の少ないクエリとは?

select_type
SIMPLE キーまたはJOIN
PRIMARY 外部クエリを示す
SUBQUERY 相関関係のないサブクエリ
DEPENDENT 相関関係のあるサブクエリ
SUBQUERY
UNCACHEABLE 実行毎に結果が変わるサブクエリ
SUBQUERY
DERIVED FROM句のサブクエリ
負荷の少ないクエリとは?

select_type
SIMPLE キーまたはJOIN
PRIMARY 外部クエリを示す
SUBQUERY 相関関係のないサブクエリ
DEPENDENT 相関関係のあるサブクエリ
SUBQUERY
UNCACHEABLE 実行毎に結果が変わるサブクエリ
SUBQUERY
DERIVED FROM句のサブクエリ
負荷の少ないクエリとは?

サブクエリ
• SQL内部で更にSQLを発行し取得する事
• 遅いのは相関関係のあるサブクエリ
負荷の少ないクエリとは?

相関サブクエリ
クエリとサブクエリが相互関係している
EXPLAIN
SELECT * FROM questions
WHERE questions.id IN
(SELECT answers.question_id FROM answers
WHERE question_user_id = questions.user_id
);
負荷の少ないクエリとは?

相関サブクエリ
クエリとサブクエリが相互関係している
EXPLAIN
SELECT * FROM questions
WHERE questions.id IN
(SELECT answers.question_id FROM answers
WHERE question_user_id = questions.user_id
);
負荷の少ないクエリとは?

相関サブクエリ
さて、このクエリは?
EXPLAIN
SELECT * FROM questions
WHERE questions.id IN
(SELECT question_id FROM answers
WHERE question_user_id = 1
);
負荷の少ないクエリとは?

相関サブクエリ
さて、このクエリは?
EXPLAIN
SELECT * FROM questions
WHERE questions.id IN
(SELECT question_id FROM answers
WHERE question_user_id = 1
);
| id | select_type
|
| 1 | PRIMARY
|
| 2 | DEPENDENT SUBQUERY |
負荷の少ないクエリとは?

相関サブクエリ
さて、このクエリは?
EXPLAIN
SELECT * FROM questions
WHERE questions.id IN
(SELECT question_id FROM answers
WHERE question_user_id = 1
);
| id | select_type
|
| 1 | PRIMARY
|
| 2 | DEPENDENT SUBQUERY |
負荷の少ないクエリとは?

相関サブクエリ
さて、このクエリは?
EXPLAIN
SELECT * FROM questions
WHERE questions.id IN
(SELECT question_id FROM answers
WHERE question_user_id = 1
);
負荷の少ないクエリとは?

相関サブクエリ
さて、このクエリは?
EXPLAIN
SELECT * FROM questions
WHERE EXISTS
(SELECT 1 FROM answers
WHERE question_user_id = 1
AND answers.question_id = questions.id
);
負荷の少ないクエリとは?

相関サブクエリ
さて、このクエリは?
EXPLAIN
SELECT * FROM questions
WHERE EXISTS
(SELECT 1 FROM answers
WHERE question_user_id = 1
AND answers.question_id = questions.id
);
負荷の少ないクエリとは?

サブクエリの問題点
• 可読性が減る
• アルゴリズムの変動リスク
• インデックス等の環境による遅延リスク
負荷の少ないクエリとは?

type
const PRIMARY KEY/UNIQUE を利用するアクセス
eq_ref JOINでPRIMARY KEY/UNIQUE を利用するアクセス
ref PRIMARY KEY/UNIQUE 以外のインデックスで等価検
索を利用するアクセス
range インデックスを利用する範囲検索。
index インデックス全体をスキャンするアクセス
(フルインデックススキャン)
ALL テーブル全体をスキャンするアクセス
(フルテーブルスキャン)
負荷の少ないクエリとは?

type
const PRIMARY KEY/UNIQUE を利用するアクセス
eq_ref JOINでPRIMARY KEY/UNIQUE を利用するアクセス
ref PRIMARY KEY/UNIQUE 以外のインデックスで等価検
索を利用するアクセス
range インデックスを利用する範囲検索。
index インデックス全体をスキャンするアクセス
(フルインデックススキャン)
ALL テーブル全体をスキャンするアクセス
(フルテーブルスキャン)
負荷の少ないクエリとは?
フルインデックススキャン
• Index condition pushdown を狙う
高頻度の場合
• 実行タイミングを変更
– 更新時に集計やソートを行う
– キュー等を利用して非同期化

• 仕様の変更
– 件数に制限をかける
– 別テーブルやデータストアに保存
負荷の少ないクエリとは?

フルテーブルスキャン
• インデックスを追加する
• Index Condition Pushdown を狙う
高頻度の場合
• フルインデックススキャンと同じ
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
• MySQL 5.6 から
• マルチカラムインデックスを有効活用す
る
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
• MySQL 5.6 から
• マルチカラムインデックスを有効活用す
る
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
ICPを使わない場合(Sex = 1, 10 ≦ Age < 20)
Sex

Age

Id

1

15

2

1

30

2

18

1

40

2

27

2

13

1

3
4
5
6

7
8
9
10
11

1

14

1

24

13

1

50

15

12

14

16

Sex

Age
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
ICPを使わない場合(Sex = 1, 10 ≦ Age < 20)
Sex

Age

Id

1

15

2

1

30

2

18

1

40

2

27

2

13

1

3
4
5
6

7
8
9
10
11

1

14

1

24

13

1

50

15

12

14

16

Sex

Age
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
ICPを使わない場合(Sex = 1, 10 ≦ Age < 20)
Sex

Age

Id

1

15

2

1

30

2

18

1

40

2

27

2

13

1

3
4
5
6

7
8
9
10
11

1

14

1

24

13

1

50

15

12

14

16

Sex

Age
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
ICPを使う場合(Sex = 1, 10 ≦ Age < 20)
Sex

Age

Id

1

15

2

1

30

2

18

1

40

2

27

2

13

1

3
4
5
6

7
8
9
10
11

1

14

1

24

13

1

50

15

12

14

16

Sex

Age
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
ICPを使う場合(Sex = 1, 10 ≦ Age < 20)
Sex

Age

Id

1

15

2

1

30

2

18

1

40

2

27

2

13

1

3
4
5
6

7
8
9
10
11

1

14

1

24

13

1

50

15

12

14

16

Sex

Age
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
ICPを使う場合(Sex = 1, 10 ≦ Age < 20)
Sex

Age

Id

1

15

2

1

30

2

18

1

40

2

27

2

13

1

3
4
5
6

7
8
9
10
11

1

14

1

24

13

1

50

15

12

14

16

Sex

Age
負荷の少ないクエリとは?

Index Condition Pushdown(ICP)
ICPを使う場合(Sex = 1, 10 ≦ Age < 20)
Sex

Age

Id

1

15

2

1

30

2

18

1

40

2

27

2

13

1

3
4
5
6

7
8
9
10
11

1

14

1

24

13

1

50

15

12

14

16

Sex

Age
負荷の少ないクエリとは?

Extra
Using where WHEREの検索条件がインデックスだけで
は解決出来ない。
Using index インデックスだけで条件を解決できる。
Using filesort クイックソートでソートを行っている。
Using temporary 実行にテンポラリテーブルが必要。
負荷の少ないクエリとは?

Extra
Using where WHEREの検索条件がインデックスだけで
は解決出来ない。
Using index インデックスだけで条件を解決できる。
Using filesort クイックソートでソートを行っている。
Using temporary 実行にテンポラリテーブルが必要。
負荷の少ないクエリとは?

Using filesort
• インデックスを追加する
• ソート条件を1テーブルに集中させる
• ソート実行を早めにさせる
負荷の少ないクエリとは?

Using filesort
このクエリの場合は?
EXPLAIN
SELECT * FROM users
WHERE active = 1
ORDER BY type_id;
+----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
|
+----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+
| 1 | SIMPLE
| users | ALL | NULL
| NULL | NULL | NULL | 191660 | Using where; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+
1 row in set (0.00 sec)
負荷の少ないクエリとは?

Using filesort
このクエリの場合は?
mysql> SHOW CREATE TABLE users G;
*************************** 1. row ***************************
Table: users
Create Table: CREATE TABLE `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
・・・
PRIMARY KEY (`id`),
KEY `index_users_on_old_id` (`old_id`),
KEY `index_users_on_provider_and_uid` (`provider`,`uid`),
KEY `index_users_on_old_random_key` (`old_random_key`)
) ENGINE=InnoDB AUTO_INCREMENT=174849 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
1 row in set (0.00 sec)
ERROR:
No query specified
負荷の少ないクエリとは?

Using filesort
このクエリの場合は?
EXPLAIN
SELECT * FROM users
WHERE active = 1
ORDER BY type_id;
負荷の少ないクエリとは?

Using temporary
• GROUP BY / DISTINCTを見直す
• 行数を考慮してJOIN条件の見直す
• サブクエリを検討する
• テーブル/カラム追加を検討する
負荷の少ないクエリとは?

Using temporary
• GROUP BY / DISTINCTを見直す
• 行数を考慮してJOIN条件の見直す
• サブクエリを検討する
• テーブル/カラム追加を検討する
高速化の仕組み

高速化の仕組み
• インデックス
• パーティション
高速化の仕組み

インデックスとは?
• 辞書の索引を付けること
• B-tree を利用している
• 正確には最下層にデータ保持するB+tree
高速化の仕組み

B-treeとは?
定義
• 根は葉であるか 2~m の子をもつ
• 根・葉以外の節は m/2 以上の子をもつ
• 根から葉までの深さが等しい
高速化の仕組み

B-treeとは?
探索方法
• 最左値より小さければ最左部分木へ進む
• 最左値より大きければ次の値と比較し、
小さければ最左の次の部分木へ進む
• 上記を反復する
高速化の仕組み

B-treeとは?

10
高速化の仕組み

B-treeとは?

5

10
高速化の仕組み

B-treeとは?

20

5

10

20
高速化の仕組み

B-treeとは?
10

47
5

20
高速化の仕組み

B-treeとは?
10

50
5

20

47

50
高速化の仕組み

B-treeとは?
10

7
5

47

20

50
高速化の仕組み

B-treeとは?
10

32
5

7

47

20

50
高速化の仕組み

B-treeとは?
10

9
5

7

9

47

20

32

50
高速化の仕組み

B-treeとは?
10

7

5

9

47

20

32

50
高速化の仕組み

B-treeとは?
10

7

5

9

47

20

32

50
高速化の仕組み

B-treeとは?
10

7

5

9

47

20

32

50
高速化の仕組み

B-treeとは?
10

7

5

9

47

20

32

50
高速化の仕組み

MySQL(InnoDB)のインデックス探索
• リーフページが大量の場合は打ち切り
ルートから探索を行う
• 9ページまで読み打ち切る(MySQL 5.6.4)
• リーフページサイズは16KB
高速化の仕組み

パーティションとは?
• 水平分割(行による分割)
高速化の仕組み

リスク
• 分割方法によっては速度が遅くなる
• 既存のクエリに分割キー条件を
追加しなければならない場合がある
• 分割キーをPKにする必要がある
• パーティション変更はサービス停止が必
要
高速化の仕組み

リターン
• メモリへの読み込みが早くなる
• 上記に伴いディスクアクセスも少なくな
る
• 可用性の高い設計になる
高速化の仕組み

テルミーの例
新着が遅くなった
• 元々 created_at で分割をしていた
• クエリに時間による制限や
ソート以外の条件が多かった
• 上記の理由でIDによる分割に変更
高速化の仕組み

テルミーの例
新着が遅くなった
EXPLAIN PARTITIONS
SELECT `questions`.* FROM `questions`
WHERE `questions`.`active` = 1
ORDER BY created_at
LIMIT 10 OFFSET 0 G;
高速化の仕組み

テルミーの例
新着が遅くなった
id: 1
select_type: SIMPLE
table: questions
partitions: p0,p1,p2,p3,…,p509,p510,p511
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1179993
Extra: Using where; Using filesort
高速化の仕組み

テルミーの例
新着が遅くなった
• IDによるソートを行うように
• 取得時にIDの範囲を指定するように
高速化の仕組み

テルミーの例
新着が遅くなった
EXPLAIN PARTITIONS
SELECT `questions`.* FROM `questions`
WHERE `questions`.`active` = 1
AND (id > 3) AND (id < 14)
LIMIT 10 OFFSET 0 G;
高速化の仕組み

テルミーの例
新着が遅くなった
EXPLAIN PARTITIONS
SELECT `questions`.* FROM `questions`
WHERE `questions`.`active` = 1
AND (id > 3) AND (id < 14)
LIMIT 10 OFFSET 0 G;
id: 1
select_type: SIMPLE
table: questions
partitions: p4,p5,p6,p7,p8,p9,p10,p11,p12,p13
type: range
possible_keys: PRIMARY,index_questions_on_id
key: PRIMARY
key_len: 4
ref: NULL
rows: 9
Extra: Using where
1 row in set (0.00 sec)
高速化の仕組み

テルミーの例
新着が遅くなった
id: 1

select_type: SIMPLE
table: questions
partitions: p4,p5,p6,p7,p8,p9,p10,p11,p12,p13
type: range
possible_keys: PRIMARY,index_questions_on_id
key: PRIMARY
key_len: 4
ref: NULL
rows: 9
Extra: Using where
1 row in set (0.00 sec)
Railsでのチューニング

Railsでのチューニング
• ActiveRecordが生成するSQLを知る
Railsでのチューニング

Railsでのチューニング
• ActiveRecordが生成するSQLを知る
• Eager Loadingを利用する
Railsでのチューニング

Railsでのチューニング
• ActiveRecordが生成するSQLを知る
• Eager Loadingを利用する
• 更新時コールバックでの集計
• バックグラウンドでの集計
Railsでのチューニング

ActiveRecordが生成するSQLを知る
Railsでのチューニング

ActiveRecordが生成するSQLを知る
to_sql
pry(main)> Question.uniq.to_sql
Railsでのチューニング

ActiveRecordが生成するSQLを知る
to_sql
pry(main)> Question.uniq.to_sql
=> "SELECT DISTINCT `questions`.* FROM `questions` "
Railsでのチューニング

ActiveRecordが生成するSQLを知る
explain
pry(main)> Question.uniq.explain
Railsでのチューニング

ActiveRecordが生成するSQLを知る
explain
pry(main)> Question.uniq.explain
Question Load (19503.4ms) SELECT DISTINCT `questions`.* FROM `questions`
EXPLAIN (9.4ms) EXPLAIN SELECT DISTINCT `questions`.* FROM `questions`
=> "EXPLAIN for: SELECT DISTINCT `questions`.* FROM `questions` n+----+-------------+----------+------+---------------+------+---------+------+--------+-------+n| id | select_type | table |
type | possible_keys | key | key_len | ref | rows | Extra |n+----+-------------+-----------+-----+---------------+------+---------+------+--------+-------+n| 1 | SIMPLE
| questions | ALL |
NULL
| NULL | NULL | NULL | 195195 |
|n+----+-------------+-----------+------+--------------+------+---------+------+--------+-------+n1 row in set (0.01 sec)n"
Railsでのチューニング

ActiveRecordが生成するSQLを知る
実装を行う前にpry等で
• 生成されるクエリ(to_sql)
• 実行計画(explain)
を確認する。
Railsでのチューニング

ActiveRecordが生成するSQLを知る
NewRelic
• Transaction tracing
• Slow SQL
の設定をオンにすれば
Railsでのチューニング

ActiveRecordが生成するSQLを知る
NewRelic
Railsでのチューニング

ActiveRecordが生成するSQLを知る
rack-mini-profiler
• https://github.com/MiniProfiler/rack-miniprofiler
• 環境毎にgemを入れるだけで簡単
Railsでのチューニング

ActiveRecordが生成するSQLを知る
rack-mini-profiler
Railsでのチューニング

ActiveRecordが生成するSQLを知る
mysqldumpslow
• スローログを合計時間で集計してくれる
• ログがあればローカルで実行できる
• gzipも読み込んでくれる
• MySQL デフォルト
Railsでのチューニング

ActiveRecordが生成するSQLを知る
mysqldumpslow
$ mysqldumpslow -t 5 -s t mysql-slow.log*
Reading mysql slow query log from mysql-slow.log

Count: 14591 Time=1.57s (22851s) Lock=0.00s (5s) Rows=10.0 (145910),
rio_slave[rio_slave]@8hosts
SELECT `questions`.* FROM `questions` WHERE `questions`.`display` = 'S'
AND `questions`.`to_user_id` IS NULL AND `questions`.`active` = N AND
(answer_last_updated_at != created_at) AND (questions.created_at >= 'S') AND
(ng_word IN (N, N)) ORDER BY answer_last_updated_at desc LIMIT N
OFFSET N
…
Railsでのチューニング

Eager Loadingを利用する
Railsでのチューニング

Eager Loadingを利用する
Eager Loading とは?
• 「積極的に読み込む」
• 先にデータを取得しておくこと
• インスタンス変数による自動キャッシュ
Railsでのチューニング

Eager Loadingを利用する
Question.limit(10).each do |q|
p “#{q.user} posted #{q.content}”
end
Railsでのチューニング

Eager Loadingを利用する
Question.limit(10).each do |q|
p “#{q.user} posted #{q.content}”
end
Question Load (9.8ms) SELECT `questions`.* FROM `questions`
User Load (5.2ms) SELECT `users`.* FROM `users` WHERE
User Load (4.1ms) SELECT `users`.* FROM `users` WHERE
User Load (4.8ms) SELECT `users`.* FROM `users` WHERE
User Load (7.9ms) SELECT `users`.* FROM `users` WHERE
User Load (5.7ms) SELECT `users`.* FROM `users` WHERE
User Load (5.4ms) SELECT `users`.* FROM `users` WHERE
User Load (4.5ms) SELECT `users`.* FROM `users` WHERE
User Load (4.4ms) SELECT `users`.* FROM `users` WHERE
User Load (4.2ms) SELECT `users`.* FROM `users` WHERE
User Load (4.4ms) SELECT `users`.* FROM `users` WHERE
Railsでのチューニング

Eager Loadingを利用する
Question.includes(:user).limit(10).each do |q|
p “#{q.user} posted #{q.content}”
end
Question Load (9.8ms) SELECT `questions`.* FROM `questions`
User Load (5.2ms) SELECT `users`.* FROM `users` WHERE
User Load (4.1ms) SELECT `users`.* FROM `users` WHERE
User Load (4.8ms) SELECT `users`.* FROM `users` WHERE
User Load (7.9ms) SELECT `users`.* FROM `users` WHERE
User Load (5.7ms) SELECT `users`.* FROM `users` WHERE
User Load (5.4ms) SELECT `users`.* FROM `users` WHERE
User Load (4.5ms) SELECT `users`.* FROM `users` WHERE
User Load (4.4ms) SELECT `users`.* FROM `users` WHERE
User Load (4.2ms) SELECT `users`.* FROM `users` WHERE
User Load (4.4ms) SELECT `users`.* FROM `users` WHERE
Railsでのチューニング

Eager Loadingを利用する
Question.includes(:user).limit(10).each do |q|
p “#{q.user} posted #{q.content}”
end
Question Load (6.9ms) SELECT `questions`.* FROM `questions`
User Load (5.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (724,
1402, 2277, 3154, 3696, 4180, 4551, 5375, 6090, 6890)
Railsでのチューニング

Eager Loadingを利用する
Question.includes(:user).limit(10).each do |q|
p “#{q.user} posted #{q.content}”
end
Question Load (6.9ms) SELECT `questions`.* FROM `questions`
User Load (5.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (724,
1402, 2277, 3154, 3696, 4180, 4551, 5375, 6090, 6890)
Railsでのチューニング

Eager Loadingを利用する
# 指定リレーショナルオブジェクトを先読み
Question.includes(:user)
Question.includes(:user, :category)
# 指定リレーションオブジェクトのフィールドを先読み
Question.includes(category: [:parent_category])
Question.includes(category:
[:parent_category, :answer_good_logs])

# 更に入れ子にも出来ます
・・・
Railsでのチューニング

Eager Loadingを利用する
# 指定リレーショナルオブジェクトを先読み
Question.includes(:user)
Question.includes(:user, :category)
# 指定リレーションオブジェクトのフィールドを先読み
Question.includes(category: [:parent_category])
Question.includes(category:
[:parent_category, :answer_good_logs])

# 更に入れ子にも出来ます
・・・
Railsでのチューニング

Eager Loadingチューニングのフロー
1. キャッシュを切る
2. rack-mini-profilerで大量発行SQLを探す
3. 対象のコントローラを探す
4. Includes を追加する
5. rack-mini-profilerで確認
Railsでのチューニング

Eager Loadingチューニングのフロー
スローログに乗らない細かいSQLも
大きな負荷削減になることが結構有ります
Railsでのチューニング

インスタンス変数によるキャッシュ
Railsでのチューニング

インスタンス変数によるキャッシュ
1接続内に複数回SQLが発行される場合
Question.first.tap do |q|
10.times { "answers count is #{q.answers.count}" }
end
Question Load (8.0ms) SELECT `questions`.* FROM `questions`
(4.2ms) SELECT COUNT(*) FROM `answers` WHERE
(3.6ms) SELECT COUNT(*) FROM `answers` WHERE
(5.3ms) SELECT COUNT(*) FROM `answers` WHERE
(3.8ms) SELECT COUNT(*) FROM `answers` WHERE
(3.8ms) SELECT COUNT(*) FROM `answers` WHERE
(5.7ms) SELECT COUNT(*) FROM `answers` WHERE
(3.8ms) SELECT COUNT(*) FROM `answers` WHERE
(3.4ms) SELECT COUNT(*) FROM `answers` WHERE
(3.8ms) SELECT COUNT(*) FROM `answers` WHERE
(5.4ms) SELECT COUNT(*) FROM `answers` WHERE
Railsでのチューニング

インスタンス変数によるキャッシュ
1接続内に複数回SQLが発行される場合
class Question < ActiveRecord::Base
・・・
def answers_count
@answers_count ||= self.answers.count
end
・・・
end
Railsでのチューニング

インスタンス変数によるキャッシュ
1接続内に複数回SQLが発行される場合
Question.first.tap do |q|
10.times { "answers count is #{q.answers_count}" }
end
Question Load (5.1ms) SELECT `questions`.* FROM `questions`
(3.6ms) SELECT COUNT(*) FROM `answers` WHERE
Railsでのチューニング

更新時コールバックでの集計
• カウント集計
• 最後に更新のあった解答
Railsでのチューニング

更新時コールバックでの集計
• カウント集計
– 更新時に親へカウントアップ/ダウン
• 最後に更新のあった投稿
– 更新時に親へ保存
Railsでのチューニング

更新時コールバックでの集計
どの様なテーブル設計の場合なの?
Users (Master)

Posts (Transaction)

name

user_id

email
…

1:n

content
…
Railsでのチューニング

更新時コールバックでの集計
どの様なテーブル設計の場合なの?
Users (Master)

Posts (Transaction)

name

user_id

email

1:n

…

content
…

UserPostStatus (Transaction)
user_id
last_post_id
posted_count
…
Railsでのチューニング

更新時コールバックでの集計
どの様なテーブル設計の場合なの?
Users (Master)

Posts (Transaction)

name

user_id

email

1:n

…

content
…

UserPostStatus (Transaction)
1:1

user_id
last_post_id
posted_count
…
Railsでのチューニング

更新時コールバックでの集計
どの様なテーブル設計の場合なの?
Users (Master)

Posts (Transaction)

name

user_id

email

1:n

…

content
…

UserPostStatus (Transaction)
1:1

user_id
last_post_id
posted_count
…

1:1
Railsでのチューニング

更新時コールバックでの集計
どの様なテーブル設計の場合なの?
Users (Master)

Posts (Transaction)

name

user_id

email

1:n

…

content
…

UserPostStatus (Transaction)
1:1

user_id

1:1

last_post_id

都度更新

posted_count

都度カウントアップ/カウントダウン

…
Railsでのチューニング

更新時コールバックでの集計
どの様なテーブル設計の場合なの?
Users (Transaction)
name

Posts (Transaction)
1:1 or n

user_id

email

content

last_post_id

…

posted_count
…
Railsでのチューニング

更新時コールバックでの集計
どの様に更新処理を行うのか?
class User < ActiveRecord::Base
attr_accessible :last_post_id
belongs_to :last_post,
class_name: Post.to_s, foreign_key: :last_answer_id
def update_last_post(post = nil)
new_last_post = post || Post.last_post(self.id).first
self.update_column :last_post_id, new_last_post.try(:id)
end
・・・
end
Railsでのチューニング

更新時コールバックでの集計
どの様に更新処理を行うのか?
class User < ActiveRecord::Base
attr_accessible :last_post_id
belongs_to :last_post,
class_name: Post.to_s, foreign_key: :last_answer_id
def update_last_post(post = nil)
new_last_post = post || Post.last_post(self.id).first
self.update_column :last_post_id, new_last_post.try(:id)
end
・・・
end
Railsでのチューニング

更新時コールバックでの集計
どの様に更新処理を行うのか?
class Post < ActiveRecord::Base
after_save { user.update_last_post(self) }
・・・
end
Railsでのチューニング

更新時コールバックでの集計
注意点
• 冗長性が高いものであること
• 再集計が可能であること
総括

総括
• データストアの知識が重要
• プロファイルでボトルネックを探せるか
• メンテナンス性とトレードオフにならない
ように設計
• データベース設計を変更する勇気を持とう
総括

参考文献
漢のコンピュータ道
http://nippondanji.blogspot.jp/2009/03/mysqlexplain.html
http://nippondanji.blogspot.jp/2009/03/using-filesort.html
http://nippondanji.blogspot.jp/2012/10/mysql-56.html
MySQL Practive Wiki
http://www.mysqlpracticewiki.com/index.php/Extra_field
SH2の日記
http://d.hatena.ne.jp/sh2/20111217
十番目のムーサ
http://d.hatena.ne.jp/psappho/20111101/1320152348
MySQL SQLオプティマイザのコスト計算アルゴリズム
http://dbstudy.info/files/20120310/mysql_costcalc.pdf
MySQL Reference Manuals
http://dev.mysql.com/doc/

Contenu connexe

Tendances

Oracle Database Connect 2017 / JPOUG#1
Oracle Database Connect 2017 / JPOUG#1Oracle Database Connect 2017 / JPOUG#1
Oracle Database Connect 2017 / JPOUG#1Noriyoshi Shinoda
 
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~Miki Shimogai
 
Elasticsearch入門 pyfes 201207
Elasticsearch入門 pyfes 201207Elasticsearch入門 pyfes 201207
Elasticsearch入門 pyfes 201207Jun Ohtani
 
AvailabilityZoneとHostAggregate
AvailabilityZoneとHostAggregateAvailabilityZoneとHostAggregate
AvailabilityZoneとHostAggregateHiroki Ishikawa
 
PostgreSQL Unconference #26 No Error on PostgreSQL
PostgreSQL Unconference #26 No Error on PostgreSQLPostgreSQL Unconference #26 No Error on PostgreSQL
PostgreSQL Unconference #26 No Error on PostgreSQLNoriyoshi Shinoda
 
[東京] JapanSharePointGroup 勉強会 #2
[東京] JapanSharePointGroup 勉強会 #2[東京] JapanSharePointGroup 勉強会 #2
[東京] JapanSharePointGroup 勉強会 #2Atsuo Yamasaki
 
MyNA JPUG study 20160220-postgresql-json-datatype
MyNA JPUG study 20160220-postgresql-json-datatypeMyNA JPUG study 20160220-postgresql-json-datatype
MyNA JPUG study 20160220-postgresql-json-datatypeToshi Harada
 
Add PLEASE clause to Oracle Database
Add PLEASE clause to Oracle DatabaseAdd PLEASE clause to Oracle Database
Add PLEASE clause to Oracle DatabaseNoriyoshi Shinoda
 
とあるイルカのバーボンハウス
とあるイルカのバーボンハウスとあるイルカのバーボンハウス
とあるイルカのバーボンハウスyoku0825
 
大規模CSVをMySQLに入れる
大規模CSVをMySQLに入れる大規模CSVをMySQLに入れる
大規模CSVをMySQLに入れるShuhei Iitsuka
 
イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情takezoe
 
[D14] MySQL 5.6時代のパフォーマンスチューニング *db tech showcase 2013 Tokyo
[D14] MySQL 5.6時代のパフォーマンスチューニング *db tech showcase 2013 Tokyo[D14] MySQL 5.6時代のパフォーマンスチューニング *db tech showcase 2013 Tokyo
[D14] MySQL 5.6時代のパフォーマンスチューニング *db tech showcase 2013 Tokyoyoyamasaki
 
Chugokudb study-20150131
Chugokudb study-20150131Chugokudb study-20150131
Chugokudb study-20150131Toshi Harada
 
PostgreSQL Unconference #29 Unicode IVS
PostgreSQL Unconference #29 Unicode IVSPostgreSQL Unconference #29 Unicode IVS
PostgreSQL Unconference #29 Unicode IVSNoriyoshi Shinoda
 
MySQL ガチBeginnerがやってみたことと反省したこと
MySQL ガチBeginnerがやってみたことと反省したことMySQL ガチBeginnerがやってみたことと反省したこと
MySQL ガチBeginnerがやってみたことと反省したことSatoshi Suzuki
 
20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)Hiromu Shioya
 

Tendances (20)

Oracle Database Connect 2017 / JPOUG#1
Oracle Database Connect 2017 / JPOUG#1Oracle Database Connect 2017 / JPOUG#1
Oracle Database Connect 2017 / JPOUG#1
 
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~
 
ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開
 
Elasticsearch入門 pyfes 201207
Elasticsearch入門 pyfes 201207Elasticsearch入門 pyfes 201207
Elasticsearch入門 pyfes 201207
 
MySQL Partition Engine
MySQL Partition EngineMySQL Partition Engine
MySQL Partition Engine
 
AvailabilityZoneとHostAggregate
AvailabilityZoneとHostAggregateAvailabilityZoneとHostAggregate
AvailabilityZoneとHostAggregate
 
PostgreSQL Unconference #26 No Error on PostgreSQL
PostgreSQL Unconference #26 No Error on PostgreSQLPostgreSQL Unconference #26 No Error on PostgreSQL
PostgreSQL Unconference #26 No Error on PostgreSQL
 
[東京] JapanSharePointGroup 勉強会 #2
[東京] JapanSharePointGroup 勉強会 #2[東京] JapanSharePointGroup 勉強会 #2
[東京] JapanSharePointGroup 勉強会 #2
 
MyNA JPUG study 20160220-postgresql-json-datatype
MyNA JPUG study 20160220-postgresql-json-datatypeMyNA JPUG study 20160220-postgresql-json-datatype
MyNA JPUG study 20160220-postgresql-json-datatype
 
Add PLEASE clause to Oracle Database
Add PLEASE clause to Oracle DatabaseAdd PLEASE clause to Oracle Database
Add PLEASE clause to Oracle Database
 
とあるイルカのバーボンハウス
とあるイルカのバーボンハウスとあるイルカのバーボンハウス
とあるイルカのバーボンハウス
 
大規模CSVをMySQLに入れる
大規模CSVをMySQLに入れる大規模CSVをMySQLに入れる
大規模CSVをMySQLに入れる
 
イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情イマドキの現場で使えるJavaライブラリ事情
イマドキの現場で使えるJavaライブラリ事情
 
[D14] MySQL 5.6時代のパフォーマンスチューニング *db tech showcase 2013 Tokyo
[D14] MySQL 5.6時代のパフォーマンスチューニング *db tech showcase 2013 Tokyo[D14] MySQL 5.6時代のパフォーマンスチューニング *db tech showcase 2013 Tokyo
[D14] MySQL 5.6時代のパフォーマンスチューニング *db tech showcase 2013 Tokyo
 
Chugokudb study-20150131
Chugokudb study-20150131Chugokudb study-20150131
Chugokudb study-20150131
 
20140920 tokyo r43
20140920 tokyo r4320140920 tokyo r43
20140920 tokyo r43
 
EDB Postgres Vision 2019
EDB Postgres Vision 2019 EDB Postgres Vision 2019
EDB Postgres Vision 2019
 
PostgreSQL Unconference #29 Unicode IVS
PostgreSQL Unconference #29 Unicode IVSPostgreSQL Unconference #29 Unicode IVS
PostgreSQL Unconference #29 Unicode IVS
 
MySQL ガチBeginnerがやってみたことと反省したこと
MySQL ガチBeginnerがやってみたことと反省したことMySQL ガチBeginnerがやってみたことと反省したこと
MySQL ガチBeginnerがやってみたことと反省したこと
 
20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)20090107 Postgre Sqlチューニング(Sql編)
20090107 Postgre Sqlチューニング(Sql編)
 

En vedette

MySQL INDEX+EXPLAIN入門
MySQL INDEX+EXPLAIN入門MySQL INDEX+EXPLAIN入門
MySQL INDEX+EXPLAIN入門infinite_loop
 
Web エンジニアが postgre sql を選ぶ 3 つの理由
Web エンジニアが postgre sql を選ぶ 3 つの理由Web エンジニアが postgre sql を選ぶ 3 つの理由
Web エンジニアが postgre sql を選ぶ 3 つの理由Soudai Sone
 
MySQL 5.7の罠があなたを狙っている
MySQL 5.7の罠があなたを狙っているMySQL 5.7の罠があなたを狙っている
MySQL 5.7の罠があなたを狙っているyoku0825
 
モバイルアプリ開発体制の継続的改善 in JaSST'14 Hokkaido
モバイルアプリ開発体制の継続的改善 in JaSST'14 Hokkaidoモバイルアプリ開発体制の継続的改善 in JaSST'14 Hokkaido
モバイルアプリ開発体制の継続的改善 in JaSST'14 HokkaidoKazuaki Matsuo
 
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術Masahiro Nagano
 
MySQL Fabricつらい
MySQL FabricつらいMySQL Fabricつらい
MySQL Fabricつらいyoku0825
 
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版Masahiro Nagano
 
GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法
GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法
GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法Satoshi Asano
 
MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話
MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話
MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話Takahiro Okumura
 
Server Monitoring Battles
Server Monitoring BattlesServer Monitoring Battles
Server Monitoring BattlesCA Technologies
 
Best Salon Image 2016: Ukranian Photo Awards (2)
Best Salon Image 2016: Ukranian Photo Awards (2)Best Salon Image 2016: Ukranian Photo Awards (2)
Best Salon Image 2016: Ukranian Photo Awards (2)maditabalnco
 
Local SEO: It's No Laughing Matter
Local SEO: It's No Laughing MatterLocal SEO: It's No Laughing Matter
Local SEO: It's No Laughing MatterGreg Gifford
 
教師節
教師節教師節
教師節clongwh
 
5 amazing facts about chocolate
5 amazing facts about chocolate5 amazing facts about chocolate
5 amazing facts about chocolateArnie Kaye Dillen
 
Driving the future of big data | PromptCloud
Driving the future of big data | PromptCloudDriving the future of big data | PromptCloud
Driving the future of big data | PromptCloudPromptCloud
 
Presentacion marisodelis duran_iseda
Presentacion marisodelis duran_isedaPresentacion marisodelis duran_iseda
Presentacion marisodelis duran_isedamarisol91
 

En vedette (20)

MySQL INDEX+EXPLAIN入門
MySQL INDEX+EXPLAIN入門MySQL INDEX+EXPLAIN入門
MySQL INDEX+EXPLAIN入門
 
Web エンジニアが postgre sql を選ぶ 3 つの理由
Web エンジニアが postgre sql を選ぶ 3 つの理由Web エンジニアが postgre sql を選ぶ 3 つの理由
Web エンジニアが postgre sql を選ぶ 3 つの理由
 
MySQL 5.7の罠があなたを狙っている
MySQL 5.7の罠があなたを狙っているMySQL 5.7の罠があなたを狙っている
MySQL 5.7の罠があなたを狙っている
 
モバイルアプリ開発体制の継続的改善 in JaSST'14 Hokkaido
モバイルアプリ開発体制の継続的改善 in JaSST'14 Hokkaidoモバイルアプリ開発体制の継続的改善 in JaSST'14 Hokkaido
モバイルアプリ開発体制の継続的改善 in JaSST'14 Hokkaido
 
ActiveRecord & ARel
ActiveRecord & ARelActiveRecord & ARel
ActiveRecord & ARel
 
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
ISUCON4 予選問題で(中略)、”my.cnf”に1行だけ足して予選通過ラインを突破するの術
 
MySQL Fabricつらい
MySQL FabricつらいMySQL Fabricつらい
MySQL Fabricつらい
 
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
 
GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法
GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法
GitHub活動を通して個人のキャリアを積みつつ仕事の成果を出す方法
 
MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話
MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話
MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話
 
Understanding Culture, Faith and Diversity in Patient Care Management
Understanding Culture, Faith and Diversity in Patient Care ManagementUnderstanding Culture, Faith and Diversity in Patient Care Management
Understanding Culture, Faith and Diversity in Patient Care Management
 
Server Monitoring Battles
Server Monitoring BattlesServer Monitoring Battles
Server Monitoring Battles
 
Best Salon Image 2016: Ukranian Photo Awards (2)
Best Salon Image 2016: Ukranian Photo Awards (2)Best Salon Image 2016: Ukranian Photo Awards (2)
Best Salon Image 2016: Ukranian Photo Awards (2)
 
Local SEO: It's No Laughing Matter
Local SEO: It's No Laughing MatterLocal SEO: It's No Laughing Matter
Local SEO: It's No Laughing Matter
 
教師節
教師節教師節
教師節
 
5 amazing facts about chocolate
5 amazing facts about chocolate5 amazing facts about chocolate
5 amazing facts about chocolate
 
Driving the future of big data | PromptCloud
Driving the future of big data | PromptCloudDriving the future of big data | PromptCloud
Driving the future of big data | PromptCloud
 
Campus comm mngrs bijeenkomst January 2013
Campus comm mngrs bijeenkomst January 2013Campus comm mngrs bijeenkomst January 2013
Campus comm mngrs bijeenkomst January 2013
 
Presentacion marisodelis duran_iseda
Presentacion marisodelis duran_isedaPresentacion marisodelis duran_iseda
Presentacion marisodelis duran_iseda
 
Zaragoza turismo 220
Zaragoza turismo 220Zaragoza turismo 220
Zaragoza turismo 220
 

Similaire à Ruby on Rails on MySQL チューニング入門

activerecord-oracle_enhanced-adapterのご紹介
activerecord-oracle_enhanced-adapterのご紹介activerecord-oracle_enhanced-adapterのご紹介
activerecord-oracle_enhanced-adapterのご紹介Kevin Toyoda
 
PostgreSQL Unconference #5 ICU Collation
PostgreSQL Unconference #5 ICU CollationPostgreSQL Unconference #5 ICU Collation
PostgreSQL Unconference #5 ICU CollationNoriyoshi Shinoda
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsShogo Sensui
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行guest5f4320
 
Microsoft SQL Serverソースエンドポイント-スタンドアロン環境での非sysadminユーザーのセットアップ
Microsoft SQL Serverソースエンドポイント-スタンドアロン環境での非sysadminユーザーのセットアップMicrosoft SQL Serverソースエンドポイント-スタンドアロン環境での非sysadminユーザーのセットアップ
Microsoft SQL Serverソースエンドポイント-スタンドアロン環境での非sysadminユーザーのセットアップQlikPresalesJapan
 
[A33] [特濃jpoug statspack on pdb oracle database 12c] 20131115 補足・続報付き
[A33] [特濃jpoug statspack on pdb oracle database 12c] 20131115 補足・続報付き[A33] [特濃jpoug statspack on pdb oracle database 12c] 20131115 補足・続報付き
[A33] [特濃jpoug statspack on pdb oracle database 12c] 20131115 補足・続報付きInsight Technology, Inc.
 
EucalyptusのHadoopクラスタとJaqlでBasket解析をしてHiveとの違いを味わってみました
EucalyptusのHadoopクラスタとJaqlでBasket解析をしてHiveとの違いを味わってみましたEucalyptusのHadoopクラスタとJaqlでBasket解析をしてHiveとの違いを味わってみました
EucalyptusのHadoopクラスタとJaqlでBasket解析をしてHiveとの違いを味わってみましたEtsuji Nakai
 
System select hint_for_h2
System select hint_for_h2System select hint_for_h2
System select hint_for_h2Jun Chiba
 
Scala EE 7 Essentials
Scala EE 7 EssentialsScala EE 7 Essentials
Scala EE 7 Essentialstnoda
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDEdcubeio
 
PostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうPostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうkasaharatt
 
Best practice laravel
Best practice laravelBest practice laravel
Best practice laravelRisa Ohnishi
 
Web技術勉強会 第25回
Web技術勉強会 第25回Web技術勉強会 第25回
Web技術勉強会 第25回龍一 田中
 
Scala.jsはじめました?
Scala.jsはじめました?Scala.jsはじめました?
Scala.jsはじめました?K Kinzal
 
PostgreSQL10徹底解説
PostgreSQL10徹底解説PostgreSQL10徹底解説
PostgreSQL10徹底解説Masahiko Sawada
 

Similaire à Ruby on Rails on MySQL チューニング入門 (20)

activerecord-oracle_enhanced-adapterのご紹介
activerecord-oracle_enhanced-adapterのご紹介activerecord-oracle_enhanced-adapterのご紹介
activerecord-oracle_enhanced-adapterのご紹介
 
PostgreSQL Unconference #5 ICU Collation
PostgreSQL Unconference #5 ICU CollationPostgreSQL Unconference #5 ICU Collation
PostgreSQL Unconference #5 ICU Collation
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.js
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 
Microsoft SQL Serverソースエンドポイント-スタンドアロン環境での非sysadminユーザーのセットアップ
Microsoft SQL Serverソースエンドポイント-スタンドアロン環境での非sysadminユーザーのセットアップMicrosoft SQL Serverソースエンドポイント-スタンドアロン環境での非sysadminユーザーのセットアップ
Microsoft SQL Serverソースエンドポイント-スタンドアロン環境での非sysadminユーザーのセットアップ
 
[A33] [特濃jpoug statspack on pdb oracle database 12c] 20131115 補足・続報付き
[A33] [特濃jpoug statspack on pdb oracle database 12c] 20131115 補足・続報付き[A33] [特濃jpoug statspack on pdb oracle database 12c] 20131115 補足・続報付き
[A33] [特濃jpoug statspack on pdb oracle database 12c] 20131115 補足・続報付き
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
EucalyptusのHadoopクラスタとJaqlでBasket解析をしてHiveとの違いを味わってみました
EucalyptusのHadoopクラスタとJaqlでBasket解析をしてHiveとの違いを味わってみましたEucalyptusのHadoopクラスタとJaqlでBasket解析をしてHiveとの違いを味わってみました
EucalyptusのHadoopクラスタとJaqlでBasket解析をしてHiveとの違いを味わってみました
 
System select hint_for_h2
System select hint_for_h2System select hint_for_h2
System select hint_for_h2
 
Scala EE 7 Essentials
Scala EE 7 EssentialsScala EE 7 Essentials
Scala EE 7 Essentials
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDE
 
PostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうPostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろう
 
hscj2019_ishizaki_public
hscj2019_ishizaki_publichscj2019_ishizaki_public
hscj2019_ishizaki_public
 
Best practice laravel
Best practice laravelBest practice laravel
Best practice laravel
 
Web技術勉強会 第25回
Web技術勉強会 第25回Web技術勉強会 第25回
Web技術勉強会 第25回
 
Gorinphp0729
Gorinphp0729Gorinphp0729
Gorinphp0729
 
Gorinphp0729
Gorinphp0729Gorinphp0729
Gorinphp0729
 
Scala.jsはじめました?
Scala.jsはじめました?Scala.jsはじめました?
Scala.jsはじめました?
 
PostgreSQL10徹底解説
PostgreSQL10徹底解説PostgreSQL10徹底解説
PostgreSQL10徹底解説
 

Ruby on Rails on MySQL チューニング入門