【Redshift】ANALYZE、VACUUMメモ

各実施で起こること

VACUUM

  • ''DELETE'' や ''UPDATE'' で発生した、削除フラグ付きの未使用領域の掃除。(SELECTで検索するとき、この領域も一応見に行って検索ミスする)
  • テーブルの ''DISTSTYLE'' の設定に従ったデータのスライス間再分散
    • ''DISTSTYLE EVEN'' だとけっこー軽い
  • テーブルに ''SORTKEY'' が設定されている場合、未ソート領域または全データの再ソート
  • テーブルを占有ロックする。参照ロック先行でかかってたら待つし、その後のトランザクションをみんな待たせる。CPU使用リソースとディスクリソースを結構使う。

ANALYZE

  • テーブルの統計情報(このディスクにこの範囲の値のデータがこんだけあってなどの情報)の刷新
    • SELECTでサンプリングしてガリガリ統計とるらしい(AWS公式ドキュメントより)
  • 前回ANALYZE実施時から、パラメータ analyze_threshold_percent の割合以上の行の変更以下の場合、内部でAnalyzeがスキップされる。
  • テーブルをロックしない。CPUリソースを結構使う。(30%ぐらい。全データ300GBぐらいのテーブルだと 十数分かかる)

確認/設定変更SQL

ANALYZE履歴取得

-- ANALYZEの実行履歴を確認するSQL。要スーパーユーザー
-- バッチの都度 CREATE/DROPするテーブルなどは名前空欄になるかも
-- 実テーブルあるけどANALYZEログないものはそもそもレコードが出ない
SELECT 
  stl_analyze.userid,            -- ANALYZE実行起因となったクエリを実行したユーザーID
  stl_analyze.xid,               -- ANALYZE実行起因となったクエリのトランザクションID
  stl_analyze.database,          -- 対象テーブルのあるdatabase
  stl_analyze.table_id,          -- 対象テーブルID
  tbl_perm_info.tablename,       -- 対象テーブル名。ログにtable_id残ってるけどシステムテーブルに名前ないものはNULL
  stl_analyze.status,            -- ANALYZE実行したか否か。Full = 全量、Skipped = コマンド実行したけど内部スキップ
  stl_analyze.rows,              -- 実行前の全体のテーブル統計サイズ。削除してcollectしていない領域も含まれる
  stl_analyze.modified_rows,     -- 実行前の最終ANALYZE実施以来の変更行数
  stl_analyze.threshold_percent, -- 実行時の、実施 or Skippedの判断となる変更行割合閾値。パラメータanalyze_threshold_percentの値。
  stl_analyze.is_auto,           -- 自動Analyzeか否か。SELECTしたとき、たまに走る
  convert_timezone('Asia/Tokyo', stl_analyze.starttime),         -- Analyze実行日時
  convert_timezone('Asia/Tokyo', stl_analyze.endtime),           -- Analyze終了日時
  convert_timezone('Asia/Tokyo', stl_analyze.prevtime)           -- Analyze前回実行日時
FROM
  -- システムテーブル
  pg_catalog.stl_analyze
  -- テーブルIDとテーブル名の組を取るサブクエリ。取るとこ間違ってる気がするけど運用できるしGoogle先生もそう言ってる
  LEFT JOIN (SELECT id, TRIM(name) AS tablename FROM pg_catalog.stv_tbl_perm GROUP BY id, name) tbl_perm_info ON (stl_analyze.table_id = tbl_perm_info.id)
--WHERE
--  convert_timezone('Asia/Tokyo', stl_analyze.starttime) >= '2018-10-10'
ORDER BY DATABASE, table_id, starttime;

ANALYZE実行閾値の取得と変更

-- 前回ANALYZE実施以降、全体の行数に対する変更行数がこの%以下であればANALYZEを内部でSkipする
SHOW analyze_threshold_percent;

-- このセッション中だけ一時的に書き換える。
-- 0だと1件以上の更新で絶対ANALYZE。auto ANALYZEでも実施されるのでバッチがむしろめっちゃ遅くなる。
SET analyze_threshold_percent to 0.01;

-- ユーザーの設定を恒久的に書き換える
ALTER USER username SET analyze_threshold_percent = 0.01;
COMMIT;

-- クラスタ全体の設定変更は、AWS WebConsoleからパラメータを設定する

ANALYZE / VACUUM 実施SQL

できれば各スキーマの所有ユーザーで実行。 ただし、面倒くさければスーパーユーザーでもできるしデメリットはない。

ANALYZE実施

個別テーブル

-- Analyze実施行数の閾値を 0 に
-- 元の値も確認しておく
SHOW analyze_threshold_percent;
SET analyze_threshold_percent TO 0;
SHOW analyze_threshold_percent;

-- Analyze実施
ANAYLZE <schema.tablename>;

-- Analyze実施行数の閾値を10に戻す
SHOW analyze_threshold_percent;
SET analyze_threshold_percent TO 10;
SHOW analyze_threshold_percent;

入っているユーザーが権限を持つ全テーブル

-- ANALYZE実施行数の閾値を 0 に
-- わかりやすいようにもとの値との比較も
SHOW analyze_threshold_percent;
SET analyze_threshold_percent TO 0;
SHOW analyze_threshold_percent;

-- ANALYZE実施
ANAYLZE;

VACUUM実施

個別テーブル

-- トランザクションを切っておかないとVACUUMが失敗する
END;

-- VACUUM実施
-- ※ インターリーブソートキーを設定しているテーブルは FULL → REINDEX にしないとだめ。
VACUUM FULL <schema.tablename>;

-- トランザクションをいちおう始めておく(後続のSQLをrollback可能にする
BEGIN;

入っているユーザーが権限を持つ全テーブル

-- トランザクションを切っておかないとVACUUMが失敗する
END;

-- VACUUM実施
-- ※ インターリーブソートキーを設定しているテーブルは FULL → REINDEX にしないとだめ。
VACUUM FULL;

-- トランザクションをいちおう始めておく(後続のSQLをrollback可能にする
BEGIN;

vue-cliで Cannot find module 'chalk' と言われてnpm run buildが通らない

めちゃはまり

事象

dockerつかってvue-cliからbuildしようとしたとき、chalkがnotfoundで落ちる。

下記DockerFileから抜粋

ENV NODE_ENV=production

WORKDIR /usr/local/app-octface-front
RUN npm install

RUN npm run build

RUN npm run build で下記エラーが出る。

Step 14/18 : RUN npm run build
 ---> Running in bd96983db14f

> oct-face@1.0.0 build /usr/local/app-octface-front
> node build/build.js

internal/modules/cjs/loader.js:583
    throw err;
    ^

Error: Cannot find module 'chalk'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
    at Function.Module._load (internal/modules/cjs/loader.js:507:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/usr/local/app-octface-front/build/check-versions.js:2:15)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)

package.jsonには chalk があるがインストール後の現物を見るとnode_modules配下に確かにディレクトリがない。おかしい。

一時解決

原因は、package.jsonにchalkなどがdevDependencies で 記述されており、npm installNODE_ENV=production だったのでインストールされなかったようだ。 ENV NODE_ENV=production を、npm install後になるように書き直した。

RUN npm install

ENV NODE_ENV=production
RUN npm run build

根本的に、vue-cliによって生成されたbuild.jsがビルドサーバーで動かないつくりになってるのは違和感。 多分開発で使っていたソースをそのままぶっこむのは何か違うんじゃないかな。試すの面倒くさいから誰か見てほしい。

vue-cliからの開発メモ

vue-cliを使ってアプリを開発しているが、これ色々とテクニックを忘れそうなので、セットアップやフレーム作った時に行ったことのメモをする。

はじめに

vue-cliは、Nodejs製のVueプロジェクトテンプレートを自動生成するツール。初めから色々なものが組み込まれている。

  • webpack(バンドラ。jsやcssや画像が100個に分かれてブラウザがロードにムキイイ!!ってなるところを黒魔術で1つのJavaScriptにしてダウンロード後展開するようにしてくれるツール)
  • ESLint(静的解析。ちょっとでもお作法に触れるとビシィ!ってErrorを出す心なきセンセイ)
  • 有名なunitテストフレームワーク単体テスト
  • 有名なe2eテスト(End to Endテスト。ヘッドレスブラウザとか使って画面操作相当のことを自動テスト)
  • ローカル開発で利用する簡易Webサーバー付き(ヤバイ)

使ってみた感じ、このフレームワーク使う?ってかんじでCLIベースで打ち込むだけであら不思議、modernなプロジェクトが出来上がっちゃう。

インストール~初回動作確認

Nodejsとvue-cliのインストール

まずはNodejsをインストール。ここらは下記にまかせる

https://nodejs.org/en/#download

それから下記に従って、vue-cliを導入

https://cli.vuejs.org/guide/installation.html

プロジェクト作成

これまた公式ドキュメントの力を借りる

https://cli.vuejs.org/guide/creating-a-project.html

開発サーバー起動

プロジェクトのルート(package.jsonが配置している)にコンソールで入って下記

npm run dev

これでESLint + コンパイル + Webpack + 開発用WebServerが http://localhost:8080 に立ち上がる。 以降、srcのコンテンツを更新するごとに自動で差分コンパイルが走って上記に反映される。

(ちなみに、このときのNODE_EVNのデフォルト値=development)

色々改良

webpackのloaderを導入

例えばVueの <style lang="scss"> 使いたいなーってとき

  1. プロジェクトのnode_moduleにwebpackのloaderを導入

プロジェクトルートにコンソールで立って

npm install sass-loader node-sass --save-dev
  1. loaderに渡すconfigを変更

多分ここはvue-loaderのバージョンによって変わる。2.9.6だと、色んな依存関係の先に下記だった

/(path to project)/build/util.js

設定内容については下記参照

http://system.blog.uuum.jp/entry/2018/01/10/110000

各ローダーに対して共通のファイルをロードさせる

/(path to project)/build/util.js

設定内容については下記参照

http://system.blog.uuum.jp/entry/2018/01/10/110000

参考文献

https://qiita.com/567000/items/dde495d6a8ad1c25fa43

http://system.blog.uuum.jp/entry/2018/01/10/110000

【JavaScript】オブジェクトを返すlambdaの簡易構文

ちょっと前までオバカで、JavaScriptの lambdaでオブジェクトを返す構文を以下にしていた

() => {
  return {
    hoge: 'huga'
  }
}

これはこう書ける

() => ({
  hoge: 'huga'
})

vue-cli インストールログ

備忘録

$ \Users\yu>npm i -g npm
+ npm@6.2.0
added 395 packages in 51.155s

$ npm install -g vue-cli
npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen)
+ vue-cli@2.9.6

$ vue init webpack oct-face

$ cd oct-face
$ npm run dev

非同期処理の悩みどころ

「UI向上のために非同期をしなければいけないんだ!!!!!!!」が界隈世間一般の語彙になって10年ぐらいだろうか、今初めてUIで簡単な非同期処理を実装してみてマルチスレッドは難しい問題を身に染みている。

タスクの取り消しは正常系

検索をかけた、でも結果が返ってこない。おそらくユーザーはキャンセルするだろう。 その挙動は、キャンセル可能であれば望ましい。

夜間に更新して日中は一切更新しないデータベースを参照するだけのアプリであれば何も考えずThreadにabort要求を投げて、また新しく検索しなおせば同じ結果になるが、 更新と参照が入り乱れる業務アプリや、動的にキャッシュを作成してやりくりする涙ぐましいリソースの切り盛りをしている基盤は、abortできる処理とできない処理を切り分けないといけないし、恐らくそれは、心地の良いUIを作るうえで障害となる。

ぱっと考えた対策

1. トランザクションのACID特性の強化

更新処理は、abortできるものにする。 例えば「法人を消したら、それに紐づく顧客情報すべても無効とする」という少なくも2テーブルを更新する処理をする際、 処理が中途半端にabortしたら「法人はつぶしたけど、顧客は生きている」などの更新不整合が発生しないようにする。

HTTP <-> client なアプリでは導入しやすいが、WindowsアプリやJavaScriptなメモリを書き換える環境では、グローバルな参照オブジェクトへのCommitタイミングを意図的に調整する工夫がいる。

2. 関連する処理を直列キューにする

顧客情報を更新・参照する処理は顧客情報関連の直列キューなど、処理の順序を保証する。 サバクラだと性能が死ぬが、クライアント内で実装する分には、GUIのロックを下げるだけの効果はある。(どうせ処理待ちは発生するので、ユーザーの自由度を少しでも上げる)