SQLAlchemy クエリの実行タイミングと中身①

## まとめ(結論だけ知りたい人用)
- SELECT
問答無用で1メソッドにつき1つクエリを発行し実行します。

- INSERT
  - autoflushを有効にしている場合
    無駄なクエリを抑制して発行・実行してくれます。

  - autoflushを無効化し、明示的にflushを使う場合
    flush()を実行するタイミングで発行・実行されます。

- UPDATE
  - autoflushを有効にしている場合
    無駄なクエリを抑制して発行・実行してくれます。

  - autoflushを無効化し、明示的にflushを使う場合
    flush()を実行するタイミングで発行・実行されます。
***
詳しく知りたい方は記事本文をどうぞ

## 概要
SQLAlchemyで発行されるCRUDに関するクエリの内容と実行タイミングを見ていきます。
この記事ではSELECT/INSERT/UPDATEについて記載します。

## SELECT
下記のコードを実行してみます。
```python
SessionClass = sessionmaker(engine, autoflush=True)
session = SessionClass()

session.query(User).all() # ここでクエリが実行されます。
session.query(User).all() # ここでクエリが実行されます。
session.query(User).all() # ここでクエリが実行されます。

session.close()
```
実行されるクエリは以下の通りとなります。
```sql
SELECT user.id AS user_id, user.name AS user_name, user.email AS user_email FROM user
SELECT user.id AS user_id, user.name AS user_name, user.email AS user_email FROM user
SELECT user.id AS user_id, user.name AS user_name, user.email AS user_email FROM user
```
全く同じ内容のクエリであっても、問答無用でSELECT文が実行されます。

## INSERT
### autoflushを有効にしている場合
下記のコードを実行してみます。
```python
SessionClass = sessionmaker(engine, autoflush=True)
session = SessionClass()

user = User(user_id="1", name="John", email="john@example.com")
session.add(user)
user2 = User(user_id="2", name="Johnwick", email="johnwick@example.com")
session.add(user2)

session.commit() # ここでクエリが実行されます。
session.close()
```
実行されるクエリは以下の通りとなります。
```sql
INSERT INTO user (id, name, email) VALUES ('1', 'John', 'john@example.com'),('2', 'Johnwick', 'johnwick@example.com')
COMMIT
```
INSERT文が1つにまとめられています。

### autoflushを無効化し、明示的にflushを使う場合
下記のコードを実行してみます。
```python
SessionClass = sessionmaker(engine, autoflush=False)
session = SessionClass()

user = User(user_id="1", name="John", email="john@example.com")
session.add(user)
session.flush() # ここでクエリが実行されます。

user2 = User(user_id="2", name="Johnwick", email="johnwick@example.com")
session.add(user2)
session.flush() # ここでクエリが実行されます。

session.commit() # ここでクエリが実行されます。
session.close()
```
実行されるクエリは以下の通りとなります。
```sql
INSERT INTO user (id, name, email) VALUES ('1', 'John', 'john@example.com')
INSERT INTO user (id, name, email) VALUES ('2', 'Johnwick', 'johnwick@example.com')
COMMIT
```
flush()が実行されるタイミングでINSERT文が実行されます。
`autoflush=True`の時に比べて無駄なクエリの発行が行われます。

## UPDATA
### autoflushを有効にしている場合
以下のコードを実行してみます。
```python
SessionClass = sessionmaker(engine, autoflush=True)
session = SessionClass()

user = User(user_id="1", name="John", email="john@example.com")
session.add(user)

user.email = "johndoe@example.com"
session.add(user)

user.name = "Johndoe"
session.add(user)

session.commit() # ここでクエリが実行されます。
session.close()
```
実行されるクエリは以下の通りとなります。
```sql
INSERT INTO user (id, name, email) VALUES ('1', 'Johndoe', 'johndoe@example.com')
COMMIT
```
INSERTとUPDATEが統合されて一つのINSERTになっていることが分かります。

### autoflushを無効化し、明示的にflushを使う場合
以下のコードを実行してみます。
```python
SessionClass = sessionmaker(engine, autoflush=False)
session = SessionClass()

user = User(user_id="1", name="John", email="john@example.com")
session.add(user)
session.flush() # ここでクエリが実行されます。

user.email = "johndoe@example.com"
session.add(user)
session.flush() # ここでクエリが実行されます。

user.name = "Johndoe"
session.add(user)
session.flush() # ここでクエリが実行されます。

session.commit() # ここでクエリが実行されます。
session.close()
```
実行されるクエリは以下の通りとなります。
```sql
INSERT INTO user (id, name, email) VALUES ('1', 'John', 'john@example.com')
UPDATE user SET email='johndoe@example.com' WHERE user.id = '1'
UPDATE user SET name='Johndoe' WHERE user.id = '1'
COMMIT
```
flush()を実行するたびにクエリが発行されていることが分かります。