1on1で気をつけている7つのこと

みなさんの会社では1on1はやっていますか?

私の会社では会社の仕組みとして1on1をやっています。 1on1って何すれば良いの?という方のために私がメンターとして1on1を運営する中で気をつけていることをまとめたいと思います。

これがきっかけで1on1を始められる方が増えて現場が円滑になれば良いな。

7つのことと書いていますが多分増えます。今は絞り出して7つだった。

1on1の目的

  • 業務上困ったことを相談したりする場
  • 目標の振り返り、確認の場
  • 雑談

基本的には、業務なので業務中心の話をします。とはいえ、他の話をしたり聞いたりして現在どういう状況なのか?ということを知っておくことは大切です。

1on1をする上で気をつけていること

  • あなただけの時間ですよ
    • メンターをやる人は多分忙しい、ミーティングも多い、気軽に声をかけるのがはばかられることもある
    • だからこそ、1on1をしているときはあなただけの時間です、というのが重要
    • PCは見ないし、スマホもいじりません(議事録は取るけど)
    • 緊急の場合は必ず一言断ってから
  • 必ず閉鎖空間で行う
    • 変な意味ではなく、何を言っても誰にも聞かれない、という空間を作る
    • 恥ずかしいこと、他人に聞かれたくないことを言いやすくなる
      • 例えば、「昇進したいです!」とはオープンな場では言いにくい
    • ミーティングルームが取れない場合は次週にスキップするくらい大切にしている
  • 否定しない
    • (なんだかテクニックみたいで嫌だけど、)否定されたら普通は次相談しようとは思わない
    • 否定されたがっている人以外は普通は嫌だ。自分も嫌だ。
  • 一緒に考える、提案する
    • 命令されたら業務、業務の一環だけど業務じゃない(表現が難しい)
    • 答えを渡すのではなく一緒に作る。なので同じ問題でも解決策が人それぞれになる
  • 毎回決まったフォーマットを利用している
    • 何を聞かれるのかわからないのは不安なので大体なにを聞かれるかを予測できるようにする
    • アジェンダは毎回共有すると良い
  • 前回話したことを踏まえた上でアジェンダを作る
    • 前回〇〇について話していたけど今はどう?
    • 一回きりではなく連続していることを意識する
    • というより問題解決が目的なら決着するまで追いかける
    • 不満があるなら現在どうかを確認する
  • 同じペースで行う
    • 必要に応じて回数は増やしても減らすことは基本的にない
    • ただしそもそものペースを落とすことはある
    • 業務の一環でやっているので雑談しかしてなくても業務

1on1をやってみて

  • メンティーの成長はもちろんメンターも成長する(かもしれない)
  • 本当は業務に直接関係ない人ともやると新鮮なんだろうな、とは思う

1on1を始める前に読んだ本

MySQLについていろいろ書いてみる

まずはRDB共通なものを書いてMySQLのことを挟んでいく。自分用のメモとして眠っていたものを転載。

ACIDとトランザクション

  • ACIDとは
    • 原子性 (Atomicity)
    • 一貫性 (Consistency)
    • 分離性 (Isolation)
    • 持続性 (Durability)
  • ACIDはトランザクションの概念と密接に結びついている
  • トランザクションを保証する概念
  • トランザクションは、独立していて、確定すると継続され、ALL OR NOTHINGで一貫しているもの
  • 特に複数のテーブルを更新しているときには矛盾が発生する危険がある

トランザクション分離レベル

  • ACIDのIのこと
  • MySQL(InnoDB)がサポートしているのは以下のレベル
    • SERIALIZABLE
      • 複数のトランザクションが並列実行された場合でも、それぞれが直列に実行された場合と同じ結果が生成されることが保証される
    • REPEATABLE READ
      • 同じセッションの間は、同じ読み取り結果が保証される
    • READ COMMITTED
      • 同じセッションの間でも、他のトランザクションが変更し、かつコミットしたデータが読み取られる
    • READ UNCOMMITTED
      • 同じセッションにおいて、他のトランザクションがコミットしなくても、変更したデータが見える
  • ただし、分離レベルによらず、SQL文の実行以外、整合性制約をチェックするときのスキーマ定義の暗黙の読み込みや、参照整合性制約によって実行される参照動作の実行において、P1〜P3(後述)は発生しない
  • 上に行くほど、並列性が低い代わりにデータの一貫性、結果の再現性が高い
  • 詳細は以下の通り
  • ただし、InnoDBREPEATABLE READでもファントムリードが発生しないことになっている
ダーティリード ファジーリード ファントムリード
READ UNCOMMITTED 発生する 発生する 発生する
READ COMMITTED 発生する 発生する
REPEATABLE READ 発生する
SERIALIZABLE

ここが詳しい https://qiita.com/PruneMazui/items/4135fcf7621869726b4b

  • それぞれの分離レベルでSERIALIZABLEから離れれば離れるほど読み取り時に不整合が発生しやすい
  • それぞれの読み取り不整合がなんなのか

ダーティリード(P1)

  • 別のトランザクションでコミットされてないデータが読み取れる現象
  • つまりコミットしなくても読み取れるのでロールバックするとデータが異なることになる

ファジーリード(P2)

  • 別のトランザクションで更新されたデータを読むことにより、一貫性がなくなる現象
  • つまり自分がコミットする前に、更新されたデータが更新前後で異なる値として取得される

ファントムリード(P3)

  • 別のトランザクションで挿入されたデータが見えることにより、一貫性がなくなる現象
  • ファジーリードとの違いは更新と挿入

他にも

ダーティーライト(P0)

失われた更新(ロストアップデート)(P4)

  • 例外的
  • トランザクションT1がデータを読み出す。T2がそのデータを更新する。最後にT1がT2が更新した値の前に基づいてデータを更新しコミットする。T2の更新が消える。

CURSOR STABILITY分離レベル

  • というものが存在しているが、READ COMMITTEDSQLカーソルに対するロック動作なので割愛

ロック

  • MySQLには、というよりDBにはロック機構が存在している。理由は、マルチユーザーで単一のリソースにアクセスするのでリソース競合が発生するため。正しく更新(INSERT,UPDATE,DETELE)されるようにするための仕組みがロック
  • MySQLのロック
    • ロックの種類( https://dev.mysql.com/doc/refman/5.6/ja/innodb-record-level-locks.html )
      • レコードロック
        • クラスタインデックスを使って取得されるロック
        • 更新対象のレコードのみロックできれば最も理想的なロックになる
      • ギャップロック
        • インデックスレコード間のギャップ、先頭インデックスレコードの前や末尾インデックスレコードのあとのギャップをロックする仕組み
        • キーを指定して以上とかでロックをかけるとほぼテーブルロックとかになる怖いやつ
      • ネクスキーロック
        • ロッキングリードにおいてファントムを防ぐために用いられる仕組み
        • これは行ロックとギャップロックを組み合わせたもの
        • ロック対象の次の値までをロックすることでファントムリードを防ぐ(ファントムリードは別トランザクションで挿入されたデータが見えてしまう現象のため)
        • select ~ for updateでロックした場合、データが挿入できなければファントムリードは防げる。ただし、並列性はSERIALIZABLEほどではないがプレーンなREPEATABLE READよりは下がる
    • 専有レベル(lock mode)

MVCC(multi version concurrency control)

ノンロッキングリードとロッキングリード

  • MVCCはノンロッキングリードでしか用いられない
  • ノンロッキングリードとは?
    • ノンロッキングとは行にロックをかけないという意味
    • ロッキングは行にロックをかける
  • これは、 select ~ for updateもしくはselect ~ lock in share modeを使うか否かによって取得される結果が異なるということである
  • ノンロッキングリードで読み取られるのは古いバージョンのデータなので、最新のデータが何であろうと、ロックされていようがいまいが構わない。そのような場合でしか、MVCCは用いられない。
  • つまりは、MVCCはリード性能を高めるための仕組みであって更新時には問題を起こす可能性がある
  • ファントムリード(別のトランザクションで挿入されたデータが見えること)が防げているのはノンロッキングリードのときのみでロックありでリードするロッキングリードの場合はMVCCの対象から外れて最新のデータが見える(つまりはファントムリードが発生する)

インデックス

  • InnoDBクラスタインデックスという構造を採用している
  • クラスタインデックスはデータがインデックスのリーフノード上に格納されている
  • Oracleみたいにインデックスとデータ領域が分かれているわけではない(今は知らん)
  • 主キーのインデックス上にデータが存在している。そのため、主キー検索すると爆速(一回の走査でデータも取れちゃうため)
  • あとはセカンダリインデックスというものがある。
  • これがいわゆるインデックスというもの。
  • 独自に指定して作成するインデックス(create index ~で作成されるインデックス)はすべてこれ
  • セカンダリインデックスを使う場合は、セカンダリインデックスを走査してからクラスタインデックスを走査するので効率が悪い
  • とは言ってもそういう仕組みのDBだってあるしそこまで問題にはならないのでは?
  • 複合インデックスを用いたカバリングインデックスとかを使うと効率上がる(インデックスだけ見れば良いので)
  • とは言え、インデックス設定しまくるのは良くないのでご利用は計画的に。(インデックスショットガン)

オンラインDDL

  • MySQL5.6から一部のDDLがオンラインで実行できるようなった(書き込みでロックが発生しなくなった)
  • 少なくともインデックス作成はオンラインでできる。ただし、IO負荷やCPU負荷は考慮すること
  • 力尽きたのであとは以下のリンクを参照してください

dev.mysql.com

docker環境にPythonの実行環境を用意する

Macでgensimが読み込めないエラーが発生していた件で、問題の切り分けのためにDockerを使ってPythonの実行環境を作成してそこで色々試してみた話 結局、ライブラリを最新版より1つ古いものを使うようにすれば良いという結果になったけどクリーンな環境をサクッと用意できるのはDockerのメリットだなーと実感した。

参考にした、というよりほぼこちらの内容のまま(ありがとうございます) qiita.com

Dockerfile

FROM python:3
USER root

RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN apt-get install -y vim less
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools

docker-compose.yml

version: '3'
services:
  python3:
    restart: always
    build: .
    container_name: 'python3'
    working_dir: '/root/'
    tty: true
    volumes:
      - ./:/root/

Dockerfileとdocker-compose.ymlがあるディレクトリで以下のコマンドを実行

$ docker-compose up -d --build
$ docker exec -it python3 bash

コンテナの中に入る。 試したかったのはgensimなのでこれだけインストール

$ python -m pip install gensim
# 実際は
$ python -m pip install gensim==3.5.0

Dockerfileに含めておきたいときはこんな感じ

RUN pip install --no-cache-dir gensim==3.5.0

--no-cache-dir オプションがないとValueError: numpy.ufunc has the wrong size, try recompiling. Expected 192, got 216 のエラーが出る

gensimの読み込みで実行時エラーが発生する

意外と日本語で検索にヒットしないのでメモ。

発生したエラーはこんな感じ

>>> from gensim.models import word2vec
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/site-packages/gensim/__init__.py", line 5, in <module>
    from gensim import parsing, corpora, matutils, interfaces, models, similarities, summarization, utils  # noqa:F401
  File "/usr/local/lib/python3.7/site-packages/gensim/corpora/__init__.py", line 6, in <module>
    from .indexedcorpus import IndexedCorpus  # noqa:F401 must appear before the other classes
  File "/usr/local/lib/python3.7/site-packages/gensim/corpora/indexedcorpus.py", line 15, in <module>
    from gensim import interfaces, utils
  File "/usr/local/lib/python3.7/site-packages/gensim/interfaces.py", line 21, in <module>
    from gensim import utils, matutils
  File "/usr/local/lib/python3.7/site-packages/gensim/matutils.py", line 1076, in <module>
    from gensim._matutils import logsumexp, mean_absolute_difference, dirichlet_expectation
  File "__init__.pxd", line 872, in init gensim._matutils
ValueError: numpy.ufunc has the wrong size, try recompiling. Expected 192, got 216
>>> 

インストールされているバージョンは 3.6.0

$ pip show gensim
Name: gensim
Version: 3.6.0
Summary: Python framework for fast Vector Space Modelling
Home-page: http://radimrehurek.com/gensim
Author: Radim Rehurek
Author-email: me@radimrehurek.com
License: LGPLv2.1
Location: /usr/local/lib/python3.7/site-packages
Requires: scipy, numpy, six, smart-open
Required-by: 

バージョンを一個前(3.5.0)に戻したらエラーが消えた

$ pip install gensim==3.5.0

そもそも他の人でも起きているのか謎い。。 ただ、Docker環境を作って検証したけど発生したのできっと他にも困っている人がいるはず!

MySQLのインデックスは1つのテーブルにつき1つしか使われないとは限らない

タイトルが全てですが、その通り。 MySQLにはインデックスマージというものが存在するということを最近知った。

詳細は以下のドキュメントを参照してほしい。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 8.2.1.4 インデックスマージの最適化

必ずしも使われるわけではないけど、1つのテーブルにつきインデックスは1つしか使われないものと思っていた認識が誤りだった。

create table user(
    id int,
    last_name varchar(20),
    first_name varchar(20),
    nickname varchar(20)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

こんな感じのテーブルがあるとしてインデックスを貼ります。

CREATE INDEX idx_first_name ON user(first_name); 
CREATE INDEX idx_last_name ON user(last_name); 
CREATE INDEX idx_nickname ON user(nickname); 

データを何件か入れて以下のSQLを実行して実行計画を取得する。

explain
select *
from user
where first_name like 'テスト%' or last_name like 'テスト%' or nickname like 'テスト%';

インデックスを貼っていない場合

+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
|    1 | SIMPLE      | user  | ALL  | NULL          | NULL | NULL    | NULL |  200 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+

インデックスを貼っている場合

+------+-------------+-------+-------------+-------------------------------------------+-------------------------------------------+----------+------+------+--------------------------------------------------------------------------+
| id   | select_type | table | type        | possible_keys                             | key                                       | key_len  | ref  | rows | Extra                                                                    |
+------+-------------+-------+-------------+-------------------------------------------+-------------------------------------------+----------+------+------+--------------------------------------------------------------------------+
|    1 | SIMPLE      | user  | index_merge | idx_first_name,idx_last_name,idx_nickname | idx_first_name,idx_last_name,idx_nickname | 63,63,63 | NULL |    3 | Using sort_union(idx_first_name,idx_last_name,idx_nickname); Using where |
+------+-------------+-------+-------------+-------------------------------------------+-------------------------------------------+----------+------+------+--------------------------------------------------------------------------+

では、複合インデックスだとどうなるか?既存のインデックスを消して以下のインデックスを追加し、確認する

CREATE INDEX idx_multi ON user(first_name, last_name, nickname); 
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
|    1 | SIMPLE      | user  | ALL  | idx_multi     | NULL | NULL    | NULL |  200 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+

なるほど。orで検索する場合は、複合インデックスを使っても使われることはなく1つ1つのカラムに対してインデックスを貼ることでインデックスマージが効いてパフォーマンスが上がる可能性が高いということらしい。 今回のケースでは Using sort_union が使われているが公式ページを見ると他にも種類があるようです。

今回の機能はMySQL5以降は有効とのことでMariaDBMySQL両方で試してみました。こうゆうとき、dockerとか便利ですよね〜と言いたいとこだったけど最新版のMariaDBでエラーが発生して時間かかった。結局バージョンを10.0まで落とすことで解決したけど。

docker-compose.yml

version: '2'

services:
  maria:
    image: mariadb:10.0
    restart: always
    volumes:
      - ./data/mariadb/:/var/lib/mysql
    ports:
      - "3307:3306"
    expose:
      - "3307"
    environment:
      MYSQL_ROOT_PASSWORD: root
    user: "1000:50"
  mysql:
    image: mysql
    restart: always
    volumes:
      - ./data/mysql:/var/lib/mysql
    ports:
      - "3308:3306"
    expose:
      - "3308"
    environment:
      MYSQL_ROOT_PASSWORD: root

mariadb:10.2 で出ていたエラーは以下の通り。時間があったら調べよう

[Warning] InnoDB: Failed to set O_DIRECT on file./ibdata1;OPEN: Invalid argument, ccontinuing anyway. O_DIRECT is known to result in 'Invalid argument' on Linux on tmpfs, see MySQL Bug#26662.
[Note] InnoDB: Highest supported file format is Barracuda.
[Note] InnoDB: 128 out of 128 rollback segments are active.
[Note] InnoDB: Creating shared tablespace for temporary tables
[Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
[Note] InnoDB: File './ibtmp1' size is now 12 MB.
[Note] InnoDB: Waiting for purge to start
[Note] InnoDB: 5.7.21 started; log sequence number 1603633
[Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
[Note] InnoDB: Buffer pool(s) load completed at 180304  4:52:55
[Note] Plugin 'FEEDBACK' is disabled.
[ERROR] Could not open mysql.plugin table. Some plugins may be not loaded
[Note] Recovering after a crash using tc.log
[ERROR] Can't init tc log
[ERROR] Aborting