PHPKansai 2016 Memo



# Composer


* ストレス開発駆動
* 3年続けた結果できたよー

# 大量のデータを困ってませんか？


@kunit

- Cronバッチが終わらない…
- 馬鹿みたいにでかいデータの対処…

## BigQuery in GCP

Full Managed.

* AWS RedShift
	* 落とすに落とせないのと、時間課金なのでおかねかかる


Github が Google のこれを使って何かを解析しているみたい。

### BigQuery

* RDB ではない。
* MapReduce　で使える
* 癖ある
* WebAPI
	* PHPライブラリある
		* RedShift は PostgreSQL 互換なので Libpq でつながる
	* WebAPIなので対象言語幅は広くて楽

## Data Import

- Load
	- GCS Google Cloud Storage
	- ファイルアップロード
	- Stream Insert
		- 0.01$/200 MB 
	- 基本無料
- Copy
	- Table to Table
- Select
	- $5 / 1TB
		- 1TB/Monthly 無料
	- Select * from T1,T2,T3 → Union になる
		- Googleの中の人「これは失敗だった」

## 癖

* 頑張ってIndexを張ったり、SQLを改善して速くなることはない
* 集計で裏で回してデータ保存させる手法でやる
* ResourceOver の下限がわからない
	* 中の人「リミットを11にしたらいけるんじゃない（金払え）」
* Selectしかない
	* Update は無い
	* Delete は無い
	* テーブルのデータを変えたいなら、テーブル消して、ロードする

## おかね

- データ保存料金は安い
- すぐに使いたいならお金を払えばいいみたい
- クエリー料金
	- 料金発生ポイント
		- select name,address from ds.member where age >= 30 limit 100
		- name,address の列のデータ量に対して料金発生
		- age の列のデータ量に対して料金発生
	- select * from ds.member
		- 全ての列のデータ量になるので使っちゃダメ
	- table名に日付を付けれる
		- 日付rangeを付けられる
	- 10TB Limit がある

## 注意事項

- 500/503 エラーが多い
	- Googleイベントがあるとエライことになる

# ORMユーザ対談

お昼後なので眠いでござる。


- ORM 実装が沢山あって、それぞれの違いを知りたい

## PDO

```php
<?php
$stmt = $pdo->query('select * from books where id=1;');
$book = $stmt->fetch();
$book['title'];
```

### Eloquent ORM

In Laravel.

- Model を継承してActiveRecodeっぽいかんじ

```php
class Book extends Illuminate\Database\Eloquent\Model\Model {}

$book = Book::find(1);
$book->title;
```

### Doctrine

- Symfonyで
- 何も継承しない
- Javaから続く伝統的なORM

```php
class Book
{
	private $id;
	private $title;
}

$repo = $doctrine->getRepository('BookBundle:Book');
$repository->find(1)->getTitle();
```

### CakePHP

- CakePHP2 は配列
- CakePHP3 はEntityObject
- 規約ベースなので、テーブルが規約に則っていれば、クラスは作らなくても取得できる

```php
<?php
class BooksTable extends Cake\ORM\Table {}
class Book extends Cake\ORM\Entity {}

$table=TableRegistry::get('Books')->get(1)->title;
```

## 関連性

select * from books left join authors on authors.id = books.author_id;

### Eloquent

```
<?php

class Book extends Model
{
    public function author() { return $this->belongsTo(Author::class); }
}

// 二つのSQLを発行
Book::find(1)->author->name;
```

### Cake

```
<?php
class BooksTable extends Table
{
	public function initialize(array $config){
		param::initialize($config);
		$this->belongsTo('Authors');
	}
}

// ..どうやってとる?

```

### Doctrine

アノテーションに書く。ながい…

EAGER => join した形。

## N+1問題

EAGER/LAGER 問題

### Eloquent


それぞれ別々のクエリーを延滞発行するので、必要分投げる。

```php
<?php
$books = Book::with('author')->get();
```

最低でも二回SQLは出る。

### Doctrine

基本はLagerだけど、取った分のキャッシュをする。EntityManager がレイジーの発生はauthor数まで。

### CakePHP

Lager 機能ないので、LagerLoadPluginを入れないとだめ。なので基本 join する。

## オブジェクトの同一性

$author->books[0]->author; これは同じ？

### CakePHP

$author->books[0]->author; は取ってこれない。

### Eloquent

無頓着。もっかい取りに行くだけ。

### Yii2

(なぜ今頃…)

`->inversedOf('author');`

### Doctrine

`$author->getBooks()[0]->getAuthor()`

- EntityManager が扱っているので、

## 100万件バッチ処理

PHPのMySQLが死ねる。

### Cake3

PDOのfetchが走る。今はデフォルトではないけど、オプションで `mysql_buffer_query:true`にしてやる必要があるっぽい。

(三年分の競馬データが回せた)

### 他は？

- Eloquentは死にますので、chunkメソッドでlimit/offsetを使え。
- Doctrine は死にます。DBRMでlimit/offsetを使う。

### 残り

3秒で終わり

# Laravel DI Container

みかかねさん

## conteinr への登録

```
<?php

// シングルトン
app()->singleton(User::class, function(){
    return new User();
});

// 毎回新規作成する
app()->bind(HogeService::class, HogeService::class);

// 取得 / 登録してなくても自動的にnewする
$hoge = app(HugaService::class);


```

## ライブラリ化のバージョニング

- git subtree
- Composer Path Repository
	- type:"path",url:"./lib/auth/"
	- vendor 外にあるディレクトリをautoloadに入れる
	- repository に type:path を入れると良い

# PHPerに知ってほしいRDBの事

DBの寿命はAppより長い = 付き合いが長くなっていく。

sodaiさん

## 対象DB

MySQL5.7 / PostgreSQL9.5?

活用事例/Security の話はしない。

## 検索とIndex

検索: Btree Index => where/GroupBy/OrderBy で使われる

- MySQL は検索時にIndexは一つしか使わない。
- 重複が少ないほうが良い
- 結果が少ないほうが良い
	- 全体10%〜30%の少ないと使う


### 実行計画

- Explain をみる
	- レコードを実レコードに合わせる
	- 統計情報を最新にする
		- 本番からdumpして、ローカルに入れても少ないままなので、refreshする必要ある
	- 実行結果が正しいことを試す
- 素振り大事
	- MySQL Workbench
		- 虫眼鏡マークのボタンを押すと実行計画を見せてくれる
			- 赤（インデックス聞いていない
			- 黄色（将来遅くなるかも
			- 緑
			- 青（最速
		- 相関サブクエリは遅い
			- Index効いているとJoinと同じように速くなる
			- Joinは掛け算（100行x100行)
			- Joinはアルゴリズムの一つ
		- Joinするなら
			- データを小さくしてから
			- Index を利用したJOINをする
				- 正規化大事
		- シンプル・拘束
			- 難しいことをしない設計力が大事
	-  PostgreSQL
		- Indexは複数使える
		- そもそもINDEXたくさんある
		- 相関サブクエリは速い
		- JOINのアルゴリズムも複数ある
		- 式INDEX
			- substr とか使っても、実行結果Indexを使うことができる
		- でもRDBの基本はMySQLと一緒

### Schemaless

正規化の話

- データは
	- 消せない
	- 変更できない
	- 追加で対応
	- 不整合が内容にするために
		- 正規化！
	- ジェイウォークはなぜダメ？
		- 検索死ぬ　京都の検索で東京都
		- 集計で死ぬ　できない…
		- 更新ができない　部分更新ができない
	- 回答者と質問と回答を別々にする
	- スキーマ変更しなくてもいいように
		- MySQL => JSON型(5.7〜), PostgreSQL -> JSON型
	- 正しいJSONであることが担保
	- インデックスはれる
		- mysql
		- `select * from demo_json where json_extract(properties '$.name') like 'hoge';`
		- 仮想列を作って、Indexをはる(5.7.5~)
		- 制約ができない（Unique制約や外部キー制約がない）
	- 自由な保存と正しく守る、はトレードオフ
		- 使うのにOKな時
			- JSONと他のテーブルが直接関係しない
			- 中の値をUPDATEしない
			- INSERT/SELECTが大半の構造
		- そもそもORMが死ぬ
		- ご利用は計画的に。


### アンチパターン

- DELETE_FLAG
	- 9とかNULLが入っている(なぜ9…？)
- 非正規化
	- 基本的に正規化したほうが速い
	- 少ないデータだと、キャッシュでメモリーに残っている事が多い
- 外部キーレス設計
	- 正規化も外部キー制約もデータを守るためにある
- そもそもRDB勉強しよう
	- データベース実践入門・SQLアンチパターン
	- 使い方も大事
		- 10年戦えるデータ分析入門
		- SQLデータ入門
- ある日突然重くなる
	- DB は蛇口、コップはメモリー、コップはあふれた瞬間に重くなる


### まとめ

* ドキュメントみる
* 実行計画を見る
* DB問題は忘れた頃にやってくる
* サーバ問題は休日中に来る
* アプリケーション問題は納期前にくる
* RDBの知識は寿命が長い
	* 覚えていれば長い間役に立つ
	* データが死ねば皆死ぬ
	* RDBは歴史長い→いろんな経験談から学ぶ


RDBはいいぞ