leaning diary Rails

【Learning Diary36】DISTINCTとuniq /バルクインサート/transaction/網羅方法

重複をまとめるDISTINCTとuniq

DISTINCTは、SELECT文の実行結果の重複レコード(データ行)を1つにまとめるSQL構文です。

 

以下のように、SELECT 文に続けて記載します。

 

SELECT DISTINCT 列名,列名… FROM テーブル名

 

Railsでは、重複のないレコードを取得するのにdistinctメソッドがあります。

 

参照:Railsドキュメント 重複のない値を取得

 

なお、配列から重複した要素を取り除いた新しい配列を返すメソッドにuniqがあります。

 

参照:instance method Array#uniq

 

コードとしては同じようにかけるのですが、distinctはDB側、uniqはアプリケーション側での処理という違いがあり、発行されるSQLには違いがあります。

 

>> User.where(name: "Sen. Clayton Robel").distinct
  User Load (0.3ms)  SELECT DISTINCT "users".* FROM "users" WHERE "users"."name" = ?  [["name", "Sen. Clayton Robel"]]
=>
[#<User:0x000000010cb75a18
  id: 86,
  name: "Sen. Clayton Robel",
  email: "examplexxxxxxx@rxxxxxxxxx.org",
  created_at: Sun, 26 Feb 2023 12:24:15.634053000 UTC +00:00,
  updated_at: Sun, 26 Feb 2023 12:24:15.634053000 UTC +00:00,
  password_digest: "[FILTERED]",
  remember_digest: nil,
  admin: false,
  activation_digest: "$2a$12$6jiYgoXa9Cjq2UTZXoAwfeMRTm9sy/xxxxxxxxxxxxxxxxxx",
  activated: true,
  activated_at: Sun, 26 Feb 2023 12:24:15.413305000 UTC +00:00,
  reset_digest: nil,
  reset_sent_at: nil>]
>> User.where(name: "Sen. Clayton Robel").uniq
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."name" = ?  [["name", "Sen. Clayton Robel"]]
=>
[#<User:0x000000010cf57140
  id: 86,
  name: "Sen. Clayton Robel",
  email: "examplexxxxxxx@rxxxxxxxxx.org",
  created_at: Sun, 26 Feb 2023 12:24:15.634053000 UTC +00:00,
  updated_at: Sun, 26 Feb 2023 12:24:15.634053000 UTC +00:00,
  password_digest: "[FILTERED]",
  remember_digest: nil,
  admin: false,
  activation_digest: "$2a$12$6jiYgoXa9Cjq2UTZXoAwfeMRTm9sy/xxxxxxxxxxxxxxxxxxxxxx",
  activated: true,
  activated_at: Sun, 26 Feb 2023 12:24:15.413305000 UTC +00:00,
  reset_digest: nil,
  reset_sent_at: nil>]

 

uniqは、レシーバをアプリのメモリに展開して処理することになるので、メモリの消費があるという点も考慮する必要があります。

バルクインサート

バルク(bulk)は「体積、容量、大量」といった意味のある英単語です。

 

バルクインサートは、テーブルに複数のレコードを追加したいときに便利な手法です。

 

通常だと1レコードずつINSERTが発行されてしまうので、保存したいデータを一度配列に入れて一気に保存します。

 

この方法だと、処理途中で不具合が生じることがないというメリットもあります。

 

参照:Rails bulk insertのパフォーマンス比較 (Railsのinsert_allとactiverecord-import)

 

transactionメソッド

ビジネスにおけるトランザクションとは「商取引」を指します。

 

一方、IT分野におけるトランザクション処理とは、一連の操作を一つの処理単位としてまとめたものです。

 

Railsで使えるtransactionは、分割不可能な複数のレコードの更新を1つの単位にまとめるメソッドです。

 

参照:Railsドキュメント transaction

 

transactionメソッド内で例外が発生すると、そのトランザクションは自動的にロールバックされます。

 

つまり、トランザクション内での変更がデータベースに適用されず、変更前の状態に戻ります。

 

例外が発生すると、トランザクションの中で行ったすべての変更がアトミック(不可分)に取り消されるため、データベースの整合性が保たれます。

 

ホワイトボックステストのテストデータの選定

命令網羅:すべての命令が最低1回。

分岐網羅:すべての分岐が最低1回。

条件網羅:ここの条件の真偽をそれぞれ最低1回。

複数条件網羅:複数ある条件の組み合わせをすべて試す。

 

-leaning diary, Rails