Entity Framework&MySQLでテーブルを作り直すときの注意

マイグレーションをリセットLink して元のデータをリストアする時、以下の条件に当てはまるエンティティがある場合注意が必要です。

  • ナビゲーションプロパティを持っている(→テーブルに外部キーが設定されている)状態でプロパティを追加した(特にshort, integer, long integer等整数型)
  • エンティティ定義しているソースコードの最後以外の行にプロパティを追加し、Add-Migrationした(ソースコード上のプロパティの順番が追加していった順になっていない)
問題はカラムの順番です。何が起こるかというと、プロパティ追加前、テーブルにはナビゲーションプロパティの外部キーを保存するためのカラムがあります。特にKey属性などを設定してない場合、参照先のIdカラムと同じinteger型になるでしょう。ここに新しいプロパティを追加すると、カラムの順番の最後に入ります。
Id integer primary key
Name varchar(30)
NavigationId integer (参照先のKeyカラムの型)
NewPropterty integer
次にマイグレーションを整理してテーブルを作り直すと、ナビゲーションプロパティのカラムが最後に入ります。
Id integer primary key
Name varchar(30)
NewPropterty integer
NavigationId integer (参照先のKeyカラムの型)

リストアは作り直した空テーブルへの実行となりますから、mysqldumpにはno-create-info(-t)オプションを付けることになると思います。これで出力されるファイルにはカラムの順番情報がありません。リストア先のテーブルもId, Name, NavigationId, NewPropertyの順番でカラムが並んでいる前提になってます。

このダンプファイルを使って作り直したテーブルにリストアするとNewPropertyとNavigationIdの値が入れ替わって保存されます。NewPropertyがvarcharなどNavigationIdと異なる型になっている場合はエラーなどになるでしょうが、同じ型の場合エラーなく保存されます。外部キー整合性のチェックはリストア時には行われないようです(やったらめちゃくちゃ重くなりそうだし)。結果ナビゲーションプロパティはでたらめなデータを参照します。

上記の内容がよく分からない、マイグレーションを重ねすぎて条件に合致するか分からない場合は、complete-insertオプションを付けてmysqldumpを実行した方が安全です。ダンプ・リストア共に劇的に遅くなりますが。

昔の記憶ですがPostgreSQL(8.1)もダンプはこういう仕様(オプション付けないとカラムの順番を保存しない)だったような。テーブル大きいとダンプ・リストアも高速化したいですからねぇ。

保険のためにデータベースのフルダンプ(テーブル作成SQL込み)を取ってなかったら爆死だったな…

— posted by mu at 09:47 am   commentComment [0]  pingTrackBack [0]

Entity Framework 6.1.3 & MySQL 5.6でマイグレーションが失敗する 2

Update-Databaseを実行すると、なぜか対象のDBがフレッシュだと誤認→マイグレーションを最初から当てようとする→既に存在するテーブル名で作成しようとしてエラーとなる。

半日かけても原因が分からず、__MigrationHistoryが壊れてしまったのかもしれないと思い込むことにする。一度Rollbackなんてしたからその時おかしくなったのだろうか。

今回の変更は新規テーブルの追加のみだったのですが、カラム数と外部キーが多く手動はちとめんどくさいので以下の手段で。

  1. MySQLに新しいデータベース(スキーマ)を作成。Entity Frameworkで用いるユーザーに必要な権限を与える。
  2. App.configのConnection Stringを新しいデータベースを対象とするように書き換える。この時のApp.configは開始プロジェクトのもの。
  3. Update-Database実行。新しいデータベースにテーブルが作成される。
  4. 新しいデータベースからマイグレーションで追加されるテーブルと__MigrationHistoryをデータ付きでdump。
  5. $ mysqldump -uroot -p -hlocalhost 新データベース名 __MigrationHistory 追加テーブル1 追加テーブル2 ... > migration.mysqldump
    
  6. 既存データベースにリストア
  7. $ mysql -uroot -p
    mysql> use 既存データベース
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    mysql> drop table __MigrationHistory;
    Query OK, 0 rows affected (0.82 sec)
    
    mysql> source migration.mysqldump
    

ConnectionStringを元データベースに戻し、Update-Database -Scriptを実行(-Scriptオプションは実際に実行されないように)でさらに適用するマイグレーションが無いことを確認して完了。

[余談] 今回マイグレーションかける直前にmysqlのディレクトリのスナップショットを取ってあったので焦らずに済んだのですが、普段取らないのになぜ今回取る気になったのだろう?

[参考]

— posted by mu at 12:03 pm   commentComment [0]  pingTrackBack [0]

FreeNASのUSBメモリが壊れた

設定のバックアップ取ってなかった (T^T)

基本USBメモリに対してはリードオンリーのシステムだからそうそう壊れないだろうと思ってたのですが、I/Oエラーというメッセージが。同容量のUSBメモリにddでコピーしてみたのですが、Pythonのファイルが破損したようで起動中にエラーで止まる。そこに同バージョンのFreeNAS上書きしたら設定全部初期化された状態。

どうせ設定しなおしならとFreeNASを9.2から9.3に上げたのですが、/のファイルシステムがufsからZFSに変わったんですね(同時にパーティションテーブルもGPTに)。ん? ZFS…ミラーリングできるということ? てことで8GBのメモリ2本差して9.3インストール時に両方指定すると、ミラーリング構成になっているっぽい。

どうもufsの頃から可能だったようですが全然知らなかった。NASなんて長期間耐久性求められるOSをUSBメモリになんて怖いことさせるなと思ってたのですが、こういう仕掛けだったんですね。

データとJailを保存するZFSは無事だったのと、初めて構築した時のメモを残してあったので、IPアドレス・NTP・ユーザー・CIFS・Jail rootを設定しなおしたらあっさり復活したのが不幸中の幸い。そのうちホットスペア用にもう一本USBメモリ挿すことにしよっと。

— posted by mu at 12:00 pm   commentComment [0]  pingTrackBack [0]

大きなinnodbテーブルにcreate index

blog20150622-TempSizeOnCreateIndex

行数150M、サイズ550GBなんていう一枚テーブルをinnodbで作ってしまいました。4TB HDD使ってるのでまだまだ溜め込めますが、こんな量のデータを1つのテーブルに入れることが何か間違っているような気がする。

こうなるとインデックス無しではまともにデータは取り出せませんので、まだテーブルが小さかった頃に数個作ってありました。で、恐れていた事態、インデックスの追加。幸いにもMySQL 5.6ではテーブルをロックせずにインデックスを追加・削除できるLink ようになったので、何日かかるかわからないけどcreate index文を実行。翌朝見ると異常終了orz

そういえば昨日の帰り際、MySQLのCPU使用率が10%前半に落ちてたな(コマンド開始時は30~50%)、メモリが足りないのかと思い、innodb_buffer_pool_sizeLink を2GB→6GBに増やして再挑戦。mysqldは順調に実メモリは消費しましたが、仮想メモリに手を出す様子はなし。

しばらく様子を見ていると、/の入っているHDD残量が少しずつ減っているのを発見。ですが前述の通り仮想メモリは増えてない。はて?

ネットで情報を探していると、たどり着いたのがこれLink

tmpdirについて少し補足します。MySQLがtmpdirに作成した一時ファイルはlsなどのコマンドでは見ることができません。これはMySQLが一時ファイルを作成したあと、すぐに削除してしまうためです。 LinuxなどのOSでは、ファイルを削除してもそのファイルをオープンしているプロセスがある限り実際の削除は行われません。逆に言えば、こうしておくことでプロセス終了時に一時ファイルが自動的にクリーンアップされるというわけです。lsofコマンドであればMySQLが作成した一時ファイルを確認することができます。
書かれている通りにlsofをやってみると
# lsof -p 2249
COMMAND  PID  USER   FD   TYPE             DEVICE     SIZE/OFF   NODE NAME
(省略)
mysqld  2249 mysql   39u   REG               0,39   5445255168   3534 /var/tmp/mysql.zUtW7u/ibDLGxdb (deleted)
たすかに~。/var/tmpにディレクトリを作っていてサイズが増えていっているけど、lsで/var/tmp/mysql.zUtW7uを見ても空っぽ。増える速度はおおよそ20GB/日(画像参照)。/の容量からして昨晩使い果たして落ちたという理由は合点がいく。

応急策としてiSCSIサーバから800GB融通してもらって/に追加。btrfsなのでインデックス作成終わったら外そうと思ってますが、今考えたら追加800GB単独でフォーマットして/var/tmpにマウントした方が安全だったな…

そのほかの環境
  • CPU: Haswell Xeon 3.5GHz
  • OS: OpenSUSE 13.2 (VMware ESXi 5.5上)
  • DBMS: MySQL 5.6.17-2.1.12 (yastにてインストール)
  • ファイルシステム: btrfs (OS用に10GB、MySQL用に4TB)
  • VMのメモリ: 4GB→8GB
[参考]

[2015/6/26 追記]/var/tmp増量後に再挑戦も翌朝失敗。忘れたころにやってくるOOM KillerLink 。topで見るとメモリを12GBほど要求しているらしい。swap増量、/proc/(mysqldのPID)/oom_adjに-17を書き込んで応戦、9時間後に3度目の正直で成功。

— posted by mu at 03:52 pm   commentComment [0]  pingTrackBack [0]

RM burger&break

blog20150607-RM_burger_and_break

最近第2次ハンバーガーマイブームが来ています。第1次はアメリカ出張時英語しゃべれなくてもメニュー指差して買えるから

WORKING!!!イベントLink 前に秋葉原に寄ったのでハンバーガー屋検索したら出てきたのがここLink 。食事系のサイト見たら分かると思いますが、入っているビルは上から下までメイドカフェて所なんですが、ここは至って普通の雰囲気な店。内装、音楽、至ってまとも。電波要素もないし、萌えの押し売りもない。店員の一人がメイド服なのを除けば。彼女の存在がむしろそこでは浮いている。ビルのオーナーがメイドを入れることを賃貸条件にしているのではないかと思うほど。

写真は今日の日替わり(?)ズッキーニわさびバーガー。わさびはほんのり聞かせてある程度。バンズは全粒粉。パティは肉汁ぼたぼたということもなくあっさりした味。いかにも手作りですっていういびつな形がいい。全体的にあっさり味でまとまっていてよかったですが、ポテトはちょっと塩効き過ぎかな。このあっさり味でギネスは合うのだろうか?

客が少なくゆったりできるけど、逆に少ないので店がやっていけるかが心配。3年は続いているようだから、すぐになくなったりはしないと思いたいけど。

— posted by mu at 11:40 pm   commentComment [0]  pingTrackBack [0]

T: Y: ALL: Online:
ThemeSwitch
  • Basic
Created in 0.0249 sec.
prev
2017.7
next
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31