やる気がストロングZERO

やる気のストロングスタイル

DBスペシャリストの問題で出てくる「テーブルサイズ見積もり計算」の解き方

必要になる数値

[見積もり行数(行)]
テーブルの総行数の見積もり。
そのテーブルが最大でどれくらいの行数になるのかの見積もり

[平均行サイズ(バイト)]
テーブルの行長が可変の場合、そのテーブルの平均行サイズ

[ページサイズ(バイト)]
扱われるデータ単位であるページのサイズ。

[ページヘッダサイズ(バイト)]
ページのヘッダ領域(ユーザーデータが入らない)のサイズ

[空き領域率(%)]
ページに、ここに指定されたパーセンテージ領域が空き領域として確保される。

[バッファサイズ(ページ)]
メモリ上にバッファとして保持しておくページ数(下記計算では未使用)

[データ所要量(バイト)]
テーブルの総バイト数

データ所要量を求めるには?

1ページあたりで使えるサイズを求める

1ページあたりで使えるサイズ = (ページサイズ - ページヘッダサイズ)* (1 - 空き領域率)

1ページあたりに入る行数を求める

1ページあたりに入る平均行数 = 1ページあたりで使えるサイズ / 平均行サイズ

何ページ必要になるのかを求める

必要ページ数 = 見積もり行数 / 1ページあたりに入る平均行数

データ所要量を求める

データ所要量 = 必要ページ数 * ページサイズ

【Docker】長期稼働でi-nodeを使い切ってしまう?

※一時解消はできたが原因解明には至らず。

Dockerの勉強の一環で、Twitterの投稿から画像リンク(コスプレ関係)のurlを収集して一覧しているwebサービスをEC2インスタンス一つにDockerコンテナで構築している。

http://cos.mixmaru.com

構成

appサーバーコンテナ:Nginx、uWSGI、Django
dbサーバーコンテナ:Postgresql

appサーバーコンテナで10分に1度スクレイピングを実行している。

現象

先日urlを叩いてみるとステータスコード500のNginxのエラー表示画面になっていた。

nginxのエラーログを見てみると

2019/03/22 14:31:17 [alert] 13#13: *9631 write() to "/var/log/nginx/access.log" failed (28: No space left on device) while logging request, client: (ip_address), server: , request: "GET / HTTP/1.1", upstream: "uwsgi://127.0.0.1:8000", host: "cos.mixmaru.com"

調査

ディスク容量が無いと言われているっぽいので、dfコマンドで調べてみたが容量は残っている。(というか、それほど容量を食うような事はしていないはず)

コンテナ側で容量制限などに引っかかっているのかと思い、docker-compose exec app bashで中に入ろうとしたが、

failed to write all bytes for _bisect.so

とエラーが出て入れず。

調べるとi-nodeを使い切っているとの事らしい。

df -iを実行してみるとたしかに100%になっているものがある。

なにか細かいファイルを大量に作成しているのだろうか、、?

一時対応

ここまで調べた時点でとりあえず、docker-compose restartを実行したらi-nodeの数が3%まで減って正常にアクセスできるようになった。

Rubyのメソッド引数メモ

Rubyのメソッド定義時の引数のパターンをメモ

飾りなし

def some_method(a)
    puts a
end

some_method 100  # 100

飾りなし(デフォルト値指定あり)

def some_method(a=100)
    puts a
end

some_method  # 100

可変長引数(配列受け取り)

def some_method(*a)
    p a
end

some_method 1, 2, 3  # [1, 2, 3]

キー指定

def some_method(a:)
    puts a
end

some_method  a: 100  # 100

キー指定(デフォルト値指定あり)

def some_method(a: 100)
    puts a
end

some_method   # 100

可変長引数(キー指定受け取り)

def some_method(**a)
    p a
end

some_method a: 1, b: 2, c: 3  # {:a=>1, :b=>2, :c=>3}

ブロック

def some_method(&block)
    block.call 100
end

some_method do |value|
    puts value
end   # 100

※&blockはyieldで代用可能

上記全タイプの引数を同時に定義する場合(定義できる順番があるっぽい)

class SomeClass
  attr_accessor :a, :b, :c, :d, :e, :others, :block

  def some_method(a, b, c="c", *d, e: "e", **others, &block)
    @a = a
    @b = b
    @c = c
    @d = d
    @e = e
    @others = others
    @block = block
  end
end

# 使用
obj = SomeClass.new
obj.some_method "a", "b", "c", "d1", "d2" , e: "e", f1: "f1", f2: "f2" do |greet|
  greet
end

# 結果
obj.a # "a"
obj.b # "b"
obj.c # "c"
obj.d # ["d1", "d2"]
obj.e # "e"
obj.others # f1=> "f1", f2=> "f2"
obj.block.call "hello" # "hello"

DBスペシャリスト勉強メモ

候補キーを全て洗い出す問題

※推移的関数従属や部分関数従属があればそれも記載するような問題

言葉に馴染みがないので何を問われているのかがそもそもわからなかったりした。

候補キーとは

候補キーとは「主キーとなる候補」の事らしい。
「主キーになる候補が副数ある?」と混乱したが、これは普段見るテーブルは正規化が行われているからで、ここで問われるときに提示される「関係スキーマ」は正規化されていないことが多く主キーになる候補が副数あったりする。

例:
電子会議室投稿(電子会議室番号、議題、分野番号、分野名、表示順、作成者ユーザーID、投稿番号、投稿本文、投稿者ユーザーID)
※ちなみにこの関係スキーマと一緒に各項目の説明も一緒に記載されていたりする。それを見ながら従属判断をする。

以下が主キー(これが決まればデータが一意に特定できるもの)として使えそうだと導き出せた。

{電子会議室番号, 投稿番号}
「電子会議室番号」が決まれば「議題」「分野番号」「表示順」「作成者ユーザーID」が決まる。また、「分野番号」が決まることによって「分野名」が決まる(推移的従属性)
「投稿番号」が決まれば、「投稿番号」「暴行者ユーザーID」が決まる。また、「電子会議室番号、投稿番号」が決まることによって「投稿本文」が決まる

{分野名, 表示順, 投稿番号}
「分野名, 表示順」が決まることによって「電子会議室番号」が決まる。あとは上記と同じ。

うーむ、、理解できているか怪しい。。なんとなく解けるが突き詰めて定義を学ぼうとすると混乱してくる。

関数従属性

Aが決まれば自動的に決まってくる値(B)があれば、これは関数従属性があると言える A -> Bと表記する

副数の値が関数従属性に関わる場合もある。 AとBが決まればCが決まる場合 {A, B} -> Cと表記する

Aが決まれば、BとCが決まる場合 A -> {B, C}と表記する

部分関数従属性

上記の関数従属性でいう{A, B} -> Cの時、 別途B -> Dという関数従属性があるなら、これを部分関数従属といえる。 ただし、Dは他の関数従属性のキーになっている場合は部分関数従属性があるとは言えない

推移的関数従属性

上記の関数従属性でいうAが決まればBが決まり、Bが極まればCが決まる場合 A -> B -> C これを推移的関数従属性という。

システムの説明があって、テーブル設計の問題点などについての問題

細かい挙動をイメージしだすと全体像がわからなくなってしまう事が多かった。

最初に問題文を読むときに、定義されているテーブルにどういう感じでレコードが追加されていくのかをイメージしながら読み、 そのレコードのキーは何になるのかをイメージしておくと全体像を見失わないで済む。

【rails】コード読んだメモ

rubyのコードリーディングの練習でrailsのコードを少し読んだのでメモ

railsでのautoloadについて

railsではActiveSupportというmoduleが使われていて、色々便利な機能を提供してくれているらしい。
その一つにActiveSupport::Autoloadがあって、これをextendすると、 デフォルトのautoloadがオーバーライドされ、シンボル名だけでファイルパスを指定することなくautoloadを出来るようになるっぽい。 ただし、ディレクトリ構造はActiveSupport::Autoloadが想定している構造にしておく必要がある

module ActiveSupport
  extend ActiveSupport::Autoload
 
  autoload :Concern

上記で、active_support/concern.rbのConcernをautoload指定してくれるようになる。

ActiveRecordでのwhereの定義場所などについて

Modelの継承元であるActiveRecord::Baseを見ると、 whereメソッドはActive_Supportで提供されているdelegateメソッドで委譲されている。
※delegeteメソッドもActiveSupportの機能

委譲先はallメソッドによって導きだされる。

例えば、SomeModel.where("条件")を実行した場合
Relationクラスのインスタンス[SomeModel]が委譲先として導きだされ、Relation#whereが実行される。

whereメソッドはQueryMethodsモジュール(query_methods.rb)に定義されており、Relationにてincludeされている。

【Rails】 Capybaraの使い方メモ

参考)
https://www.rubydoc.info/github/jnicklas/capybara/Capybara
https://github.com/teamcapybara/capybara
https://qiita.com/morrr/items/0e24251c049180218db4

railsへのインストール

Gemfilesへ追記し、bundle installでインストールする。
rails 5.2.2では初期インストールされていた。

使い方

参考)
https://github.com/teamcapybara/capybara#using-capybara-with-rspec

テストスクリプトの配置

spec/features/以下 または spec/systems/以下にxxxxx_spec.rbとして配置する。
※機能中心にテストするならfeatures以下、表示中心にテストするならviews以下に配置するのかと想像している。systems/以下はどのようなケースで使うべき?

記述内容サンプル

/hello/indexページにhelloと表示されているかを確認する場合

require 'rails_helper'

describe "capybaraの実験", type: :feature do
  before :each do
    # 何か事前に必要な処理などがあれば
    visit '/hello/index' # 指定urlへアクセス
  end

  # RSpecマッチャー(以下参照)を使うサンプル
  # pageはページ自体を表す
  it "アクセスできるかテストする" do
    expect(page).to have_content "hello" 
  end

  # 要素を取得して、その属性が意図しているものか確認するサンプル
  it "全ての画像タグが挿入されているか" do
    all('.imageList__img').zip(get_all_urls) do |element, expected_url|
      expect(element[:src]).to eq(expected_url)
    end
  end

  # 要素を指定して取得して、そのinnerHTMLの要素が意図しているものか確認するサンプル
  it "表示されている名前がただしいか?" do
    elm = find('#name')
    expect(elm.text).to eq("山田太郎")
  end

RSpecで使う場合のマッチャー

一覧)
https://www.rubydoc.info/github/jnicklas/capybara/Capybara/RSpecMatchers

上記サンプルのhave_contentは指定した文字列を含んでいるかどうかをチェックしてる。

capybaraのElementクラスのメソッド一覧

一覧)
https://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Element

要素に対して、クリックを行ったり、テキストを挿入したりするメソッドもある。
element[:src]のような書き方でその属性にアクセスできる。

実行方法

RSpecを実行したら実行された。

bundle exec rspec

【Rails】RSpecの使い方メモ

参考:
GitHub - rspec/rspec-rails: RSpec for Rails-3+
RSpec Expectations 3.8 - RSpec Expectations - RSpec - Relish

インストール

Gemfileに追記

# Run against the latest stable release
group :development, :test do
  gem 'rspec-rails', '~> 3.8'
end

bundle installを実行してインストール

bundle update rspec-railsを実行して初期化

model用RSpec

コマンドでRSpec用ファイル作成

rails generate rspec:model user

テスト記述サンプル

Dogモデルをテストすると仮定。
dob.nameにはunique indexが貼られているとする

require 'rails_helper'

RSpec.describe Dog, type: :model do
  context "存在するdogを取得" do
    it "取得できる" do
      dog = Dog.find_by(name: "pochi")
      expect(dog).to be_an_instance_of(Dog)
    end
  end

  context "存在しないdogを取得しようとした場合" do
    it "nilが取得される" do
      dog = Dog.find_by(name: "bobobobo")
      expect(dog).to be_nil
    end
  end

  context "nameが重複しないdogを保存しようとした場合" do
    it "保存できる" do
      dog = Dog.new(name: "hachi")
      expect(dog.save).to be true
    end
  end

  context "nameが重複するdogを保存しようとした場合" do
    it "例外が発生して保存できない" do
      dog = Dog.new(name: "pochi")
      expect{ Dog.save }.to raise_error(ActiveRecord::RecordNotUnique)
    end
  end
end

実行

bundle exec rspec

マッチャー一覧

Built in matchers - RSpec Expectations - RSpec - Relish