fixed performance issues

This commit is contained in:
Umed Khudoiberdiev 2017-11-17 10:45:01 +05:00
parent ad64db9c29
commit 65e75b4d11
13 changed files with 186 additions and 90 deletions

View File

@ -1,7 +1,7 @@
{
"name": "typeorm",
"private": true,
"version": "0.2.0-alpha.1",
"version": "0.2.0-alpha.2",
"description": "Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, WebSQL, MongoDB databases.",
"license": "MIT",
"readmeFilename": "README.md",

View File

@ -260,18 +260,19 @@ export class MysqlDriver implements Driver {
return [sql, []];
const escapedParameters: any[] = [];
const keys = Object.keys(parameters).map(parameter => "(:" + parameter + "\\b)").join("|");
sql = sql.replace(new RegExp(keys, "g"), (key: string) => {
let value = parameters[key.substr(1)];
if (value instanceof Function) {
return value();
Object.keys(parameters).forEach(key => {
sql = sql.replace(new RegExp("(:" + key + "\\b)", "g"), (key: string): string => {
let value = parameters[key.substr(1)];
if (value instanceof Function) {
return value();
} else {
if (value instanceof ArrayParameter) value = value.value;
escapedParameters.push(parameters[key.substr(1)]);
return "?";
}
}); // todo: make replace only in value statements, otherwise problems
} else {
if (value instanceof ArrayParameter) value = value.value;
escapedParameters.push(parameters[key.substr(1)]);
return "?";
}
});
});
return [sql, escapedParameters];
}

View File

@ -239,18 +239,19 @@ export class OracleDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, []];
const escapedParameters: any[] = [];
const keys = Object.keys(parameters).map(parameter => "(:" + parameter + "\\b)").join("|");
sql = sql.replace(new RegExp(keys, "g"), (key: string) => {
let value = parameters[key.substr(1)];
if (value instanceof Function) {
return value();
Object.keys(parameters).forEach(key => {
sql = sql.replace(new RegExp("(:" + key + "\\b)", "g"), (key: string): string => {
let value = parameters[key.substr(1)];
if (value instanceof Function) {
return value();
} else {
if (value instanceof ArrayParameter) value = value.value;
escapedParameters.push(value);
return key;
}
}); // todo: make replace only in value statements, otherwise problems
} else {
if (value instanceof ArrayParameter) value = value.value;
escapedParameters.push(value);
return key;
}
});
});
return [sql, escapedParameters];
}

View File

@ -353,24 +353,25 @@ export class PostgresDriver implements Driver {
return [sql, []];
const builtParameters: any[] = [];
const keys = Object.keys(parameters).map(parameter => "(:" + parameter + "\\b)").join("|");
sql = sql.replace(new RegExp(keys, "g"), (key: string): string => {
let value = parameters[key.substr(1)];
if (value instanceof Array) {
return value.map((v: any) => {
builtParameters.push(v);
Object.keys(parameters).forEach(key => {
sql = sql.replace(new RegExp("(:" + key + "\\b)", "g"), (key: string): string => {
let value = parameters[key.substr(1)];
if (value instanceof Array) {
return value.map((v: any) => {
builtParameters.push(v);
return "$" + builtParameters.length;
}).join(", ");
} else if (value instanceof Function) {
return value();
} else {
if (value instanceof ArrayParameter) value = value.value;
builtParameters.push(value);
return "$" + builtParameters.length;
}).join(", ");
} else if (value instanceof Function) {
return value();
} else {
if (value instanceof ArrayParameter) value = value.value;
builtParameters.push(value);
return "$" + builtParameters.length;
}
}); // todo: make replace only in value statements, otherwise problems
}
}); // todo: make replace only in value statements, otherwise problems
});
return [sql, builtParameters];
}

View File

@ -271,24 +271,25 @@ export class AbstractSqliteDriver implements Driver {
return [sql, []];
const builtParameters: any[] = [];
const keys = Object.keys(parameters).map(parameter => "(:" + parameter + "\\b)").join("|");
sql = sql.replace(new RegExp(keys, "g"), (key: string): string => {
let value = parameters[key.substr(1)];
if (value instanceof Array) {
return value.map((v: any) => {
builtParameters.push(v);
Object.keys(parameters).forEach(key => {
sql = sql.replace(new RegExp("(:" + key + "\\b)", "g"), (key: string): string => {
let value = parameters[key.substr(1)];
if (value instanceof Array) {
return value.map((v: any) => {
builtParameters.push(v);
return "$" + builtParameters.length;
}).join(", ");
} else if (value instanceof Function) {
return value();
} else {
if (value instanceof ArrayParameter) value = value.value;
builtParameters.push(value);
return "$" + builtParameters.length;
}).join(", ");
} else if (value instanceof Function) {
return value();
} else {
if (value instanceof ArrayParameter) value = value.value;
builtParameters.push(value);
return "$" + builtParameters.length;
}
}); // todo: make replace only in value statements, otherwise problems
}
});
});
return [sql, builtParameters];
}

View File

@ -245,23 +245,24 @@ export class SqlServerDriver implements Driver {
if (!parameters || !Object.keys(parameters).length)
return [sql, []];
const escapedParameters: any[] = [];
const keys = Object.keys(parameters).map(parameter => "(:" + parameter + "\\b)").join("|");
sql = sql.replace(new RegExp(keys, "g"), (key: string) => {
let value = parameters[key.substr(1)];
if (value instanceof Array) {
return value.map((v: any) => {
escapedParameters.push(v);
return "@" + (escapedParameters.length - 1);
}).join(", ");
} else if (value instanceof Function) {
return value();
Object.keys(parameters).forEach(key => {
sql = sql.replace(new RegExp("(:" + key + "\\b)", "g"), (key: string): string => {
let value = parameters[key.substr(1)];
if (value instanceof Array) {
return value.map((v: any) => {
escapedParameters.push(v);
return "@" + (escapedParameters.length - 1);
}).join(", ");
} else if (value instanceof Function) {
return value();
} else {
if (value instanceof ArrayParameter) value = value.value;
escapedParameters.push(value);
return "@" + (escapedParameters.length - 1);
}
}); // todo: make replace only in value statements, otherwise problems
} else {
if (value instanceof ArrayParameter) value = value.value;
escapedParameters.push(value);
return "@" + (escapedParameters.length - 1);
}
});
});
return [sql, escapedParameters];
}

View File

@ -106,18 +106,19 @@ export class WebsqlDriver extends AbstractSqliteDriver {
if (!parameters || !Object.keys(parameters).length)
return [sql, []];
const escapedParameters: any[] = [];
const keys = Object.keys(parameters).map(parameter => "(:" + parameter + "\\b)").join("|");
sql = sql.replace(new RegExp(keys, "g"), (key: string) => {
let value = parameters[key.substr(1)];
if (value instanceof Function) {
return value();
Object.keys(parameters).forEach(key => {
sql = sql.replace(new RegExp("(:" + key + "\\b)", "g"), (key: string): string => {
let value = parameters[key.substr(1)];
if (value instanceof Function) {
return value();
} else {
if (value instanceof ArrayParameter) value = value.value;
escapedParameters.push(value);
return "?";
}
}); // todo: make replace only in value statements, otherwise problems
} else {
if (value instanceof ArrayParameter) value = value.value;
escapedParameters.push(value);
return "?";
}
});
});
return [sql, escapedParameters];
}

View File

@ -163,6 +163,7 @@ export class SubjectExecutor {
// then we run insertion in the sequential order which is important since we have an ordered subjects
await PromiseUtils.runInSequence(Object.keys(groupedInsertSubjects), async groupName => {
const subjects = groupedInsertSubjects[groupName];
const insertMaps = subjects.map(subject => {
if (this.queryRunner.connection.driver instanceof MongoDriver) {

View File

@ -29,6 +29,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
*/
getQuery(): string {
let sql = this.createInsertExpression();
console.log("wtf");
return sql.trim();
}
@ -37,6 +38,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
*/
async execute(): Promise<InsertResult> {
const queryRunner = this.obtainQueryRunner();
console.log("hello execution");
let transactionStartedByUs: boolean = false;
try {
@ -47,7 +49,9 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
transactionStartedByUs = true;
}
console.log("getting value sets");
const valueSets: ObjectLiteral[] = this.getValueSets();
console.log("got value set");
// call before insertion methods in listeners and subscribers
if (this.expressionMap.callListeners === true && this.expressionMap.mainAlias!.hasMetadata) {
@ -63,8 +67,10 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
}
// execute query
console.log("get query and parameters");
const [sql, parameters] = this.getQueryAndParameters();
const insertResult = new InsertResult();
console.log("query execution");
insertResult.raw = await queryRunner.query(sql, parameters);
// load returning results and set them to the entity if entity updation is enabled
@ -201,11 +207,13 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
* Creates INSERT express used to perform insert query.
*/
protected createInsertExpression() {
console.log("getting query");
const tableName = this.getTableName(this.getMainTableName());
const returningExpression = this.createReturningExpression();
const columnsExpression = this.createColumnNamesExpression();
const valuesExpression = this.createValuesExpression();
console.log("finishing query");
// generate INSERT query
let query = `INSERT INTO ${tableName}`;

View File

@ -3,16 +3,13 @@ import {Connection} from "../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Post} from "./entity/Post";
describe.skip("benchmark > bulk-save", () => {
describe.skip("benchmark > bulk-save > case1", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
}));
before(async () => connections = await createTestingConnections({ __dirname }));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("testing bulk save of 1000 objects", () => Promise.all(connections.map(async connection => {
const posts: Post[] = [];
@ -27,7 +24,8 @@ describe.skip("benchmark > bulk-save", () => {
posts.push(post);
}
await connection.manager.save(posts);
// await connection.manager.save(posts);
await connection.manager.insert(Post, posts);
})));

View File

@ -0,0 +1,52 @@
import "reflect-metadata";
import {Connection} from "../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Document} from "./entity/Document";
describe.skip("benchmark > bulk-save > case2", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({ __dirname, enabledDrivers: ["postgres"] }));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("testing bulk save of 1000 objects", () => Promise.all(connections.map(async connection => {
const documents: Document[] = [];
for (let i = 0; i < 1000; i++) {
const document = new Document();
document.id = i.toString();
document.docId = "label/" + i;
document.context = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vel faucibus nunc. Etiam volutpat vel urna in scelerisque. Cras a erat ipsum. ";
document.label = "label/" + i;
document.distributions = [
{
weight: "0.9",
id: i,
docId: i
},
{
weight: "0.23123",
id: i,
docId: i
},
{
weight: "0.12312",
id: i,
docId: i
}
];
document.date = new Date();
documents.push(document);
// await connection.manager.save(document);
// await connection.manager.insert(Document, document);
}
await connection.manager.save(documents);
// await connection.manager.insert(Document, documents);
})));
});

View File

@ -0,0 +1,31 @@
import {Entity} from "../../../../src/decorator/entity/Entity";
import {Column} from "../../../../src/decorator/columns/Column";
import {PrimaryColumn} from "../../../../src/decorator/columns/PrimaryColumn";
@Entity()
export class Document {
@PrimaryColumn("text")
id: string;
@Column("text")
docId: string;
@Column("text")
label: string;
@Column("text")
context: string;
@Column({type: "jsonb"})
distributions: Distribution[];
@Column({type: "timestamp with time zone"})
date: Date;
}
export interface Distribution {
weight: string;
id: number;
docId: number;
}