ためすう
keep_if を使ってみる (Ruby)
2020-12-05やったこと
keep_if
を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
調査
$ irb
irb(main):001:0> a = %w[a b c d]
irb(main):002:0> a.keep_if {|v| v == 'a' || v == 'd'}
=> ["a", "d"]
block のなかで false
判定の要素を削除します。
ちなみに Array#select!
Array#filter!
でも同じことが出来ます。
irb(main):004:0> a = %w[a b c d]
irb(main):005:0> a.select! {|v| v == 'a' || v == 'd'}
=> ["a", "d"]
irb(main):006:0> a
=> ["a", "d"]
...
irb(main):009:0> a = %w[a b c d]
irb(main):010:0> a.filter! {|v| v == 'a' || v == 'd'}
=> ["a", "d"]
irb(main):011:0> a
=> ["a", "d"]
少し深ぼってみます
# Equivalent to Set#keep_if, but returns nil if no changes were
# made. Returns an enumerator if no block is given.
def select!(&block)
block or return enum_for(__method__) { size }
n = size
keep_if(&block)
self if size != n
end
# Equivalent to Set#select!
alias filter! select!
削除対象があるかどうかで、違いがあるようですね。
irb(main):012:0> a = %w[a b c d]
irb(main):013:0> a.filter! {|v| true }
=> nil
irb(main):014:0> a = %w[a b c d]
irb(main):015:0> a.keep_if {|v| true }
=> ["a", "b", "c", "d"]
コメントにある通り、削除対象がない場合に nil
を返すのか self
を返すのかで挙動が違うことが分かりました。
参考
SHOW PROFILE を使ってみる (MySQL)
2020-11-23やったこと
SHOW PROFILE を使ってみます。
確認環境
$ mysql --version
mysql Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using EditLine wrapper
調査
プロファイリング対象のクエリを発行
mysql> show variables like "%profiling%"
-> ;
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| have_profiling | YES |
| profiling | OFF |
| profiling_history_size | 15 |
+------------------------+-------+
3 rows in set (0.00 sec)
mysql> SELECT COUNT(*), created_at FROM bulk_test_org
-> GROUP BY created_at
-> ORDER BY COUNT(*) DESC
-> LIMIT 10;
+----------+---------------------+
| COUNT(*) | created_at |
+----------+---------------------+
| 8388608 | 2020-11-03 07:36:31 |
| 4194304 | 2020-11-03 07:34:32 |
| 2097152 | 2020-11-03 07:34:19 |
| 1048576 | 2020-11-03 07:34:12 |
| 524288 | 2020-11-03 07:34:07 |
| 262144 | 2020-11-03 07:34:03 |
| 131072 | 2020-11-03 07:34:01 |
| 65536 | 2020-11-03 07:34:00 |
| 32768 | 2020-11-03 07:33:59 |
| 16384 | 2020-11-03 07:33:58 |
+----------+---------------------+
10 rows in set (20.51 sec)
結果確認
mysql> SHOW PROFILES;
+----------+-------------+-------------------------------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+-------------+-------------------------------------------------------------------------------------------------------+
| 1 | 0.00901450 | select count(*), created_at from bulk_test group by created_at order by count(*) desc limit 3 |
| 2 | 0.00022100 | select * from bulk_test limit 3 |
| 3 | 0.00224100 | select * from bulk_test_org limit 3 |
| 4 | 0.00024325 | select * from bulk_test_org limit 3 |
| 5 | 0.00000075 | SELECT COUNT(*), created_at FROM bulk_test
GROUP BY created_at
ORDER BY COUNT(*) DESC
LIMIT 10 |
| 6 | 20.49806075 | SELECT COUNT(*), created_at FROM bulk_test_org
GROUP BY created_at
ORDER BY COUNT(*) DESC
LIMIT 10 |
+----------+-------------+-------------------------------------------------------------------------------------------------------+
6 rows in set, 1 warning (0.00 sec)
mysql> SHOW PROFILE;
+----------------------+-----------+
| Status | Duration |
+----------------------+-----------+
| starting | 0.000060 |
| checking permissions | 0.000008 |
| Opening tables | 0.000018 |
| init | 0.000020 |
| System lock | 0.000009 |
| optimizing | 0.000006 |
| statistics | 0.000014 |
| preparing | 0.000011 |
| Creating tmp table | 0.000030 |
| Sorting result | 0.000005 |
| executing | 0.000003 |
| Sending data | 20.480386 |
| Creating sort index | 0.009607 |
| end | 0.000435 |
| removing tmp table | 0.000028 |
| end | 0.000234 |
| query end | 0.000015 |
| closing tables | 0.001094 |
| freeing items | 0.002723 |
| logging slow query | 0.000010 |
| cleaning up | 0.003346 |
+----------------------+-----------+
21 rows in set, 1 warning (0.01 sec)
参考
Amazon RDS から CSV を出力する方法 (MySQL)
2020-11-15やったこと
Amazon RDS から CSV ファイルを出力します。
確認環境
※ RDS ではありませんが、コマンド実行元にCSVファイルを出力することで、 RDS でも同様に適用できます。
$ mysql --version
mysql Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using EditLine wrapper
$ python --version
Python 2.6.6
調査
dump 対象となるテーブル
- データベース名: test
- テーブル名: test_table
mysql> select * from test_table;
+----+------+------+------+
| id | col1 | col2 | col3 |
+----+------+------+------+
| 1 | 2 | 3 | 4 |
| 2 | 2 | 3 | 4 |
+----+------+------+------+
2 rows in set (0.00 sec)
mysqldump から CSV を生成するツールの準備
mysqldump の出力を CSV に変換するツールを使います。
git clone https://github.com/jamesmishra/mysqldump-to-csv.git
clone したファイルが下記のように配置します。
$ pwd
/home/vagrant/rds-mysql
$ chmod 755 mysqldump_to_csv.py
mysqldump から CSV を取得する
$ mysqldump -h127.0.0.1 -uroot -p test test_table -t --single-transaction | mysqldump_to_csv.py
Enter password:
1,2,3,4
2,2,3,4
標準出力で CSV データを得ることができました。
参考
やったこと
今回、Rails のキャッシュ機構で、Active Record のオブジェクトを保存すると “色々、大変なことがあるぞ” ということについて書いていきたいと思います。
ちなみにここでいうキャッシュ機構は、cache_store のことを指します。
それでは始めます。
確認環境
$ bundle exec rails --version
Rails 5.2.4.3
$ mysql --version
mysql Ver 14.14 Distrib 5.6.43, for osx10.13 (x86_64) using EditLine wrapper
検証
準備
テーブル作成
CREATE TABLE `pencils` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`maker_name` varchar(50) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC
データ登録
INSERT INTO pencils VALUES (NULL, 'maker1', NOW(), NOW());
app/models/pencil.rb
class Pencil < ApplicationRecord
end
config/environments/development.rb (抜粋)
config.cache_store = :memory_store
cache に保存する
$ bundle exec rails c
Running via Spring preloader in process 65049
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> p = Pencil.last
(1.3ms) SET NAMES utf8mb4, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
Pencil Load (0.9ms) SELECT `pencils`.* FROM `pencils` ORDER BY `pencils`.`id` DESC LIMIT 1
=> #<Pencil id: 1, maker_name: "maker1", created_at: "2020-11-08 22:45:49", updated_at: "2020-11-08 22:45:49">
irb(main):002:0> Rails.cache.write('pencil1', p)
=> true
irb(main):003:0> Rails.cache.read('pencil1')
=> #<Pencil id: 1, maker_name: "maker1", created_at: "2020-11-08 22:45:49", updated_at: "2020-11-08 22:45:49">
irb(main):004:0> Rails.cache.read('pencil2')
=> nil
クラス名を変更する (そろそろ来るぞ!)
app/models/pencil.rb を下記のように変更します。
app/models/pencil2.rb
class Pencil2 < ApplicationRecord
end
保存してある cache を読み込む
irb(main):004:0> reload!
Reloading...
=> true
irb(main):005:0> Rails.cache.read('pencil1')
Traceback (most recent call last):
1: from (irb):5
NameError (uninitialized constant Pencil)
はい。Pencil クラスがなくなってしまったので、ロードで失敗してしまいました。
これは、”色々、大変なことがあるぞ” の1つです。
対応方針
cacheストレージ使うときは、”安心なデータ” を入れる必要があります。
データ構造じゃない、value を入れるのが安心です。
例えば以下が “安心なデータ” と考えます。
- 数値 例: 123
- 文字列 例: あいう
配列、json、ハッシュもデータ構造が変わるときに対応を忘れないようにすれば、使って良いと思います。
Active Record のオブジェクトは、cacheストレージに保存しない方が安心です。
なぜかといえば、例えば、Railsのバージョンが変わったとき、ApplicationRecord
の内部の構造も変わり
読み込めなくなる可能性があるからです。
はい。実際にありました。
ApplicationRecord
は rails の本体に入っているため、この事態に気が付きにくいです。
また、システムが大きくなればなるほど、対応範囲の調査が大変になります(経験談)
まとめ
cacheストレージ使うときは、構造が変更される可能性が低いデータを入れましょう!!!
“安心なデータ” は、構造が変更される可能性が低いデータになります。
- 数値 例: 123
- 文字列 例: あいう
もちろん、配列、json、ハッシュなどを使ったほうがいいケースもあり、その場合は構造を変更するときに注意してください。
構造が変更される可能性があって、検知しづらいのが Active Record のオブジェクト
だと思います。
Active Record のオブジェクト
をcacheストレージに入れた方が良い場合があるかもしれませんが、
いまのところ、私は、Active Record のオブジェクト
をcacheストレージに使わないほうが良いと思っています。
LOAD DATA INFILE を使う (MySQL)
2020-11-08やったこと
データ登録するときに、外部ファイルを読み込む LOAD DATA INFILE
を使ってみます。
確認環境
$ mysql --version
mysql Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using EditLine wrapper
調査
対象テーブル
移行前テーブル
mysql> select count(id) from bulk_test
-> ;
+-----------+
| count(id) |
+-----------+
| 16777216 |
+-----------+
1 row in set (6.41 sec)
テーブル名は、bulk_test_1
bulk_test_2
とインクリメントします。
CREATE TABLE `bulk_test_1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`text_data` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`uniq_col` int(11) DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_col` (`uniq_col`)
) ENGINE=InnoDB AUTO_INCREMENT=17366761 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
;
insert select で投入
mysql> INSERT INTO bulk_test_2 SELECT * FROM bulk_test;
Query OK, 16777216 rows affected (1 min 33.62 sec)
Records: 16777216 Duplicates: 0 Warnings: 0
mysql> SET FOREIGN_KEY_CHECKS = 0;
Query OK, 0 rows affected (0.05 sec)
mysql> SET UNIQUE_CHECKS = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> SET AUTOCOMMIT = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO bulk_test_1 SELECT * FROM bulk_test;
Query OK, 16777216 rows affected (1 min 49.48 sec)
Records: 16777216 Duplicates: 0 Warnings: 0
LOAD DATA LOCAL INFILE
投入する CSV 例
1,dummy text34,1,2020-11-03 07:31:48,2020-11-03 07:31:48
2,dummy text58,2,2020-11-03 07:33:16,2020-11-03 07:33:16
[vagrant@localhost ~]$ time mysql -u root -p test -e "LOAD DATA LOCAL INFILE '/tmp/bulk_test3.csv' INTO TABLE bulk_test_4 FIELDS TERMINATED BY ','"
Enter password:
real 1m40.355s
user 0m0.067s
sys 0m2.468s
LOAD DATA INFILE
投入する CSV 例
1,dummy text34,1,2020-11-03 07:31:48,2020-11-03 07:31:48
2,dummy text58,2,2020-11-03 07:33:16,2020-11-03 07:33:16
mysql> LOAD DATA INFILE '/tmp/bulk_test3.csv'
-> INTO TABLE bulk_test_3
-> FIELDS TERMINATED BY ','
-> ;
Query OK, 16777216 rows affected (1 min 34.17 sec)
Records: 16777216 Deleted: 0 Skipped: 0 Warnings: 0
mysqldump で dump を流し込む
[vagrant@localhost ~]$ time mysqldump -uroot -p test bulk_test > /tmp/20201108.sql
Enter password:
real 0m47.587s
user 0m13.386s
sys 0m2.482s
投入前に別名に rename しておきます。
mysql> rename table bulk_test to bulk_test_org
-> ;
Query OK, 0 rows affected (0.02 sec)
[vagrant@localhost ~]$ time mysql -u root -p test < /tmp/20201108.sql
Enter password:
real 2m39.268s
user 0m14.920s
sys 0m2.572s
まとめ
自分の PC で検証した限りだと、INSERT INTO ... SELECT
と LOAD DATA INFILE
は、そんなに速度差はないみたいでした。
CSV 出力の時間が追加されるので、合計では INSERT INTO ... SELECT
の方が短時間で出来るかもしれません。
参考
MySQL で CSV 出力する (MySQL)
2020-11-08やったこと
MySQL のデータを CSV 出力する方法を2通りやってみます。
確認環境
$ mysql --version
mysql Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using EditLine wrapper
調査
mysqldump で CSV を出力する
mysqldump -uroot -p --tab=/tmp --fields-terminated-by=, test bulk_test
[vagrant@localhost ~]$ ls -lh /tmp/
合計 985M
-rw-rw-r-- 1 vagrant vagrant 1.6K 11月 7 11:15 2020 bulk_test.sql
-rw-rw-rw- 1 mysql mysql 981M 11月 7 11:15 2020 bulk_test.txt
mysqldump --help
より
-T, –tab=name Create tab-separated textfile for each table to given path. (Create .sql and .txt files.) NOTE: This only works if mysqldump is run on the same machine as the mysqld server.
–fields-escaped-by=name Fields in the output file are escaped by the given character.
mysql で CSV を出力する
mysql> SELECT * FROM bulk_test
-> INTO OUTFILE '/tmp/bulk_test2.csv'
-> FIELDS TERMINATED BY ','
-> ENCLOSED BY '"'
-> ESCAPED BY '"'
-> LINES TERMINATED BY '\r\n';
Query OK, 16777216 rows affected (19.63 sec)
[vagrant@localhost ~]$ ls -lh /tmp/ | grep test2
-rw-rw-rw- 1 mysql mysql 1.1G 11月 7 11:19 2020 bulk_test2.csv
大量データを作成する (MySQL)
2020-11-07やったこと
テストデータで、1000万件のデータを用意する必要があったので、
MySQL だけで完結できるようにやってみます。
確認環境
$ mysql --version
mysql Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using EditLine wrapper
調査
テーブル準備
CREATE TABLE IF NOT EXISTS `bulk_test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`text_data` varchar(20) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
;
INSERT 実行
1件目
INSERT INTO bulk_test values (null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW());
これを欲しい件数まで繰り返します。
INSERT bulk_test (id, text_data, created_at, updated_at)
SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
1 -> 2 -> 4 -> 8 … とどんどん投入データが増えていきます。
実行結果
mysql> INSERT bulk_test (id, text_data, created_at, updated_at)
-> SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 8 rows affected (0.00 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 16 rows affected (0.00 sec)
Records: 16 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 32 rows affected (0.00 sec)
Records: 32 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 64 rows affected (0.00 sec)
Records: 64 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 128 rows affected (0.00 sec)
Records: 128 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 256 rows affected (0.02 sec)
Records: 256 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 512 rows affected (0.00 sec)
Records: 512 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 1024 rows affected (0.01 sec)
Records: 1024 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 2048 rows affected (0.01 sec)
Records: 2048 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 4096 rows affected (0.03 sec)
Records: 4096 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 8192 rows affected (0.10 sec)
Records: 8192 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 16384 rows affected (0.06 sec)
Records: 16384 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 32768 rows affected (0.12 sec)
Records: 32768 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 65536 rows affected (0.22 sec)
Records: 65536 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 131072 rows affected (0.45 sec)
Records: 131072 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 262144 rows affected (1.09 sec)
Records: 262144 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 524288 rows affected (2.05 sec)
Records: 524288 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 1048576 rows affected (4.62 sec)
Records: 1048576 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 2097152 rows affected (9.64 sec)
Records: 2097152 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 4194304 rows affected (22.91 sec)
Records: 4194304 Duplicates: 0 Warnings: 0
mysql> INSERT bulk_test (id, text_data, created_at, updated_at) SELECT null, CONCAT('dummy text', CEIL(RAND() * 100)), NOW(), NOW() FROM bulk_test;
Query OK, 8388608 rows affected (44.87 sec)
Records: 8388608 Duplicates: 0 Warnings: 0
mysql> select count(*) from bulk_test;
+----------+
| count(*) |
+----------+
| 16777216 |
+----------+
1 row in set (6.51 sec)
16777216 件のレコードが出来上がりました。
unique キー制約、外部キー制約があると、もう少し複雑になるので、
ruby, python などでプログラム書いた方が速いかもしれません。
MySQL でランダムな数値を出力する (MySQL)
2020-11-03やったこと
MySQL で、テストデータを作成するときに、ランダムな数値を出力したいことがあったので
やってみます。
確認環境
$ mysql --version
mysql Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using EditLine wrapper
調査
例えば、0 ~ 5
までの数字を出力するとします。
RAND
(0 <= v < 1.0) を返すROUND(X)
四捨五入するFLOOR(X)
X 以下で最大の整数値を返す
これを組み合わせ使います。
rand の動きチェック
mysql> SELECT RAND();
+---------------------+
| RAND() |
+---------------------+
| 0.28683608517687403 |
+---------------------+
1 row in set (0.00 sec)
mysql> SELECT RAND();
+--------------------+
| RAND() |
+--------------------+
| 0.9208513711773337 |
+--------------------+
1 row in set (0.00 sec)
round の動きチェック
mysql> SELECT ROUND(2.4);
+------------+
| ROUND(2.4) |
+------------+
| 2 |
+------------+
1 row in set (0.00 sec)
mysql> SELECT ROUND(2.5);
+------------+
| ROUND(2.5) |
+------------+
| 3 |
+------------+
1 row in set (0.00 sec)
mysql> SELECT ROUND(2.47);
+-------------+
| ROUND(2.47) |
+-------------+
| 2 |
+-------------+
1 row in set (0.00 sec)
floor の動きチェック
mysql> SELECT FLOOR(2.4);
+------------+
| FLOOR(2.4) |
+------------+
| 2 |
+------------+
1 row in set (0.00 sec)
mysql> SELECT FLOOR(3.2);
+------------+
| FLOOR(3.2) |
+------------+
| 3 |
+------------+
1 row in set (0.00 sec)
mysql> SELECT FLOOR(3.5);
+------------+
| FLOOR(3.5) |
+------------+
| 3 |
+------------+
1 row in set (0.00 sec)
0 ~ 5
までの数字を出力する (ROUND + RAND)
mysql> SELECT ROUND(RAND() * 5);
+-------------------+
| ROUND(RAND() * 5) |
+-------------------+
| 1 |
+-------------------+
1 row in set (0.00 sec)
mysql> SELECT ROUND(RAND() * 5);
+-------------------+
| ROUND(RAND() * 5) |
+-------------------+
| 5 |
+-------------------+
1 row in set (0.00 sec)
これだと
- 0.0 ~ 0.4 => 0
- 0.5 ~ 1.4 => 1
となり、端っこの方でばらつくかもしれません。
なので rand() x 6
して、0... ~ 5.9...
して切り捨てすればいい感じになりそうです。
0 ~ 5
までの数字を出力する (FLOOR + RAND)
mysql> SELECT FLOOR(RAND() * 6);
+-------------------+
| FLOOR(RAND() * 6) |
+-------------------+
| 4 |
+-------------------+
1 row in set (0.00 sec)
mysql> SELECT FLOOR(RAND() * 6);
+-------------------+
| FLOOR(RAND() * 6) |
+-------------------+
| 0 |
+-------------------+
1 row in set (0.00 sec)
参考
mysqldump を使ってみる (MySQL)
2020-11-01やったこと
mysqldump を使ってみます。
確認環境
$ mysql --version
mysql Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using EditLine wrapper
$ mysqldump --version
mysqldump Ver 10.13 Distrib 5.6.25, for Linux (x86_64)
調査
dump 対象となるテーブル
- データベース名: test
- テーブル名: test_table
mysql> select * from test_table;
+----+------+------+------+
| id | col1 | col2 | col3 |
+----+------+------+------+
| 1 | 2 | 3 | 4 |
| 2 | 2 | 3 | 4 |
+----+------+------+------+
2 rows in set (0.00 sec)
mysqldump を実行する
$ mysqldump -h127.0.0.1 -uroot -p test test_table -t --single-transaction
出力結果
Enter password:
-- MySQL dump 10.13 Distrib 5.6.25, for Linux (x86_64)
--
-- Host: 127.0.0.1 Database: test
-- ------------------------------------------------------
-- Server version 5.6.25
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Dumping data for table `test_table`
--
LOCK TABLES `test_table` WRITE;
/*!40000 ALTER TABLE `test_table` DISABLE KEYS */;
INSERT INTO `test_table` VALUES (1,'2','3','4'),(2,'2','3','4');
/*!40000 ALTER TABLE `test_table` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2020-11-01 9:07:35
mysqldump オプションの説明 (mysqldump –helpより抜粋)
-t
で、データのみをdumpします。
-t, --no-create-info
Don't write table creation info.
single-transaction
--single-transaction
Creates a consistent snapshot by dumping all tables in a
single transaction.
実際に使う場合は、標準出力をファイルに書き出して、使うと思います。
dotenv を使ってみる (gem)
2020-10-31やったこと
環境変数をファイルで管理する dotenv を使ってみます。
確認環境
$ ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin17]
$ rails --version
Rails 5.2.4.1
調査
install
Gemfile
gem 'dotenv-rails', groups: [:development, :test]
$ bundle install
RAILS_ENV=development用の環境変数をセット
.env.development
HOGE1='hoge1hoge1'
HOGE2='hoge2hoge2'
rails console
$ bundle exec rails c
Running via Spring preloader in process 47643
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> ENV['HOGE1']
=> "hoge1hoge1"
irb(main):002:0> ENV['HOGE3']
=> nil
irb(main):003:0> ENV['HOGE2']
=> "hoge2hoge2"
RAILS_ENV=test用の環境変数をセット
.env.test
HOGE1='test hoge1hoge1'
HOGE2='test hoge2hoge2'
rails console
$ RAILS_ENV=test bundle exec rails c
Running via Spring preloader in process 48051
Loading test environment (Rails 5.2.4.3)
irb(main):001:0> ENV['HOGE1']
=> "test hoge1hoge1"
irb(main):002:0> ENV['HOGE3']
=> nil
irb(main):003:0> ENV['HOGE2']
=> "test hoge2hoge2"
注意!!!
現在、ドキュメントにあるこの gem はなくなってしまったみたいです。
gem 'gem-that-requires-env-variables'