-
Notifications
You must be signed in to change notification settings - Fork 1
TypeORMサポートのトライアル #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
MySQLで座標値が小数点以下3-4桁に丸められてしまう不具合については、以下のQiita記事、TypeORMドキュメントを参考に、 合わせて、
ただし、上記対応の影響かで、PostgreSQL/MySQLの初期データベース構築にさらに+1時間程度の時間がかかるようになっているかもしれません。
上記については、SQLite、PostgreSQL、MySQLでサポートされている複数行インサートを週末目処で少し試してみます。 |
| // awaitがあるため、forEachでなくforループで回す | ||
| for (let i = 0; i < paramsList.length; i++) { | ||
| const params = paramsList[i]; | ||
| await queryRunner.connection.query(preparedSql, params); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここしか見ていないので、分かりませんが、たぶん、こんな感じでできませんかねー。
const tasks = paramsList.map(params => {
return queryRunner.connection.query(preparedSql, params);
})
Promise.all(tasks);preparedSql が大きかったりすると、シリアルに実行したほうが良かったりしますが。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maskatsum こちらにつきまして、アドバイス頂き、大変ありがとうございます!🙇
今朝の時点で、手元のPC (M1 MacBook Pro)で、PostgreSQLで約2時間、MySQLで約4時間かかっていたものが、
上記の対応のみで、いずれも30分程度で処理完了するようになりました。😊
- 修正前:
- PostgreSQL:
npm start download 1050.98s user 637.60s system 22% cpu 2:02:43.84 total - MySQL:
npm start download 2806.36s user 1274.25s system 27% cpu 4:06:54.28 total
- PostgreSQL:
- 修正後:
- PostgreSQL:
npm start download 897.74s user 700.45s system 84% cpu 31:34.43 total - MySQL:
npm start download 942.74s user 273.01s system 54% cpu 37:28.01 total
- PostgreSQL:
| if (dsType === 'postgres') { | ||
| tempSql = tempSql.replace(matchedInsertOrReplace[0], 'INSERT INTO'); | ||
| tempSql = tempSql.replace(/-- /g, ''); | ||
| } else if (dsType === 'mysql') { | ||
| tempSql = tempSql.replace(matchedInsertOrReplace[0], 'REPLACE INTO'); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここは switch で分けたいですね。
あと dsType が string になっていますが、Enum にしたいですねー。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。
別ブランチ上で作業中ですが、一旦下記コミットで対応しています。
(Enumに関しては良く分かりませんでしたので一旦保留としています。明日確認させてください。)
a8cb67f
| if (matchedJSONFunctions) { | ||
| for (let i = 0; i < matchedJSONFunctions.length; i++) { | ||
| const matchedJSONFucntion = matchedJSONFunctions[i]; | ||
| if (matchedJSONFucntion.toLowerCase() === 'json_group_array') { | ||
| if (dsType === 'postgres') { | ||
| tempSql = tempSql.replace(matchedJSONFucntion, 'json_agg'); | ||
| } else if (dsType === 'mysql') { | ||
| tempSql = tempSql.replace(matchedJSONFucntion, 'json_arrayagg'); | ||
| } | ||
| } else if (matchedJSONFucntion.toLowerCase() === 'json_object') { | ||
| if (dsType === 'postgres') { | ||
| tempSql = tempSql.replace(matchedJSONFucntion, 'json_build_object'); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return { | ||
| preparedSql: tempSql, | ||
| paramKeys: keys, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
こんな感じはどうですか?
// ネスティングはなるべく浅くすると良いです。コードの可読性が上がります。
if (!matchedJSONFunctions) {
return {
preparedSql: tempSql,
paramKeys: keys,
};
}
matchedJSONFunctions.forEach(matchedJSONFucntion => {
const functionName = matchedJSONFucntion.toLowerCase();
switch (`${functionName}-${dsType}`) {
case 'json_group_array-postgress':
tempSql = tempSql.replace(matchedJSONFucntion, 'json_agg');
break;
case 'json_group_array-mysql':
tempSql = tempSql.replace(matchedJSONFucntion, 'json_arrayagg');
break;
case 'json_object-postgres':
tempSql = tempSql.replace(matchedJSONFucntion, 'json_build_object');
break;
default:
break;
}
});
return {
preparedSql: tempSql,
paramKeys: keys,
};There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。
別ブランチ上で作業中ですが、上記修正をそのまま採用させて頂き、以下のコミットで対応しています。
1de8fff
|
@maskatsum 色々とアドバイス頂き、ありがとうございます! 🙇🙏 1/25追記: 取り急ぎ、1つ目のコメント箇所に対応いたしました。残るコメントについては、週末にかけて確認するようにいたします。 🙇 |
|
ご対応ありがとうございますー。週末の打ち合わせでお話させていただくのを楽しみにしております。 |
maskatsum
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
明日、細かく説明しますが、気づいた点をコメントさせていただきますー
| let tempSql = sql; | ||
| const keys = []; | ||
| const dsType = ds.options.type; | ||
| const matchedParams = tempSql.match(/@[a-zA-Z_0-9]+/g); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tempSql.match(/@[a-zA-Z_0-9]+/g);
の部分は、RegExpEx.create を使っていただくと、正規表現のインスタンスがキャッシュされます。
また、@ は、設定値から来るものなので、ハードコーディングしてしまうと設定を変更した場合に反映されなくなってしまいます。
| export const DASH: string = '@'; |
なので以下のようにしていただくのが良いです
tempSql.match(RegExpEx.create(`${DASH}[a-zA-Z_0-9]+`, 'g'));
| if (matchedParams) { | ||
| for (let i = 0; i < matchedParams.length; i++) { | ||
| const matchedParam = matchedParams[i]; | ||
| const paramName = matchedParam.replace('@', ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
matchedParam.replace('@', '');
は
matchedParam.replace(DASH, '');
ですねー。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。
別ブランチで作業中ですが、一つ上のRegExpExと合わせて、以下のコミットで対応しています。
a971ad7
| if (matchedInsertValues) { | ||
| for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) { | ||
| const placeHolders = []; | ||
| for (let paramIdx = 0; paramIdx < paramsCount; paramIdx++) { | ||
| const placeHolder = | ||
| dsType === 'postgres' | ||
| ? `$${rowIdx * paramsCount + paramIdx + 1}` | ||
| : '?'; | ||
| placeHolders.push(placeHolder); | ||
| } | ||
| rows.push(`(${placeHolders.join(',')})`); | ||
| } | ||
| tempSql = tempSql.replace( | ||
| matchedInsertValues[0], | ||
| 'VALUES ' + rows.join(',') | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここのネストが深い部分は解消したいですねー。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
17行目の if (matchedInsertValues) { のブロックで1階層は減らせそうですが、
if (!matchedInsertValues) {
return tempSql;
}
for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
const placeHolders = [];
for (let paramIdx = 0; paramIdx < paramsCount; paramIdx++) {
const placeHolder =
dsType === 'postgres' ? `$${rowIdx * paramsCount + paramIdx + 1}` : '?';
placeHolders.push(placeHolder);
}
rows.push(`(${placeHolders.join(',')})`);
}
tempSql = tempSql.replace(matchedInsertValues[0], 'VALUES ' + rows.join(','));さらにrow/paramの2階層ループのネストを減らそうとなると、難しそうな気がしました。
書き方にあまり慣れていませんが、以下のサイトなどを参考に、forループを短縮して書くことは
可能なようでしたが、どのレベルまで対応するかは、明日、確認させてください。
https://stackoverflow.com/questions/3746725/how-to-create-an-array-containing-1-n
const rows = [...Array(rowCount).keys()].map(rowIdx => {
const placeHolders = [...Array(paramsCount).keys()].map(paramIdx => {
return dsType === 'postgres' ? `$${rowIdx * paramsCount + paramIdx + 1}` : '?';
});
return `(${placeHolders.join(',')})`;
});| await queryRunner.query('DROP INDEX IF EXISTS "dataset_key"'); | ||
| await queryRunner.query('DROP TABLE IF EXISTS "dataset_old"'); | ||
| await queryRunner.query('DROP INDEX IF EXISTS "metadata_key"'); | ||
| await queryRunner.query('DROP TABLE IF EXISTS "metadata_old"'); | ||
| await queryRunner.query('DROP INDEX IF EXISTS "rsdtdsp_rsdt_code"'); | ||
| await queryRunner.query('DROP TABLE IF EXISTS "rsdtdsp_rsdt_old"'); | ||
| await queryRunner.query('DROP INDEX IF EXISTS "rsdtdsp_blk_code"'); | ||
| await queryRunner.query('DROP TABLE IF EXISTS "rsdtdsp_blk_old"'); | ||
| await queryRunner.query('DROP INDEX IF EXISTS "town_code"'); | ||
| await queryRunner.query('DROP TABLE IF EXISTS "town_old"'); | ||
| await queryRunner.query('DROP INDEX IF EXISTS "city_code"'); | ||
| await queryRunner.query('DROP TABLE IF EXISTS "city_old"'); | ||
| await queryRunner.query('DROP INDEX IF EXISTS "pref_code"'); | ||
| await queryRunner.query('DROP TABLE IF EXISTS "pref_old"'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この辺、こんな感じに、1queryにまとめられるような気がします(試してないですー)。
await queryRunner.query(`
DROP INDEX IF EXISTS "dataset_key";
DROP TABLE IF EXISTS "dataset_old";
DROP INDEX IF EXISTS "metadata_key";
DROP TABLE IF EXISTS "metadata_old";
....
DROP TABLE IF EXISTS "pref_old";
`);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。
npm run test:system で上記の1クエリに集約できることを確認しました。
bd4193a
マイグレーションファイル内の他の箇所についても集約した方が良いか、明日、確認させてください。
Adjust dummy sqlite database path
Replace integer to smallint to save space
…mmand performance drastically
…d expect improving insert performance
a850862 to
05f4bb3
Compare
…r MySQL performance
|
アップストリームのv2.0.0(地番レベル対応分)で、SQLiteデータベースが複数(各市区町村毎)に生成される形となったことに伴い、TypeORMでの対応が難しくなったようでしたので、こちらのPRは #4 と合わせてクローズします。 |
以前、 feature/switch-better-sqlite3-to-typeorm ブランチで試行していたものを整理の上、JestのテストやPostgreSQL/MySQLで最低限の動作が通るようにしたものになります。
TODO:
~/.my.cnfで以下の設定後、mysqlサービス再起動が必要です。