diff --git a/lib/sqlTranslator.js b/lib/sqlTranslator.js index da8d82a..28204de 100644 --- a/lib/sqlTranslator.js +++ b/lib/sqlTranslator.js @@ -617,43 +617,58 @@ class SqlTranslator { }); } const fk = foreignKey || 'entityId'; - const joinFilter = { - $expr12: { - $eq: [ - { - '#attr': fk, - }, - { - '#refId': refAlia2, - '#refAttr': 'id', - } - ], - } - }; - if (!foreignKey) { - Object.assign(joinFilter, { - entity: entity2, - }); + // 对in和not in优化,不要用exists查询 + if (['in', 'not in'].includes(predicate)) { + const { stmt, currentNumber: ct2 } = this.translateSelectInner(subEntity, { + data: { + [fk]: 1, + }, + filter: filter2[attr] + }, currentNumber, filterRefAlias, option); + currentNumber = ct2; + whereText += `(${refAlia2}.id ${predicate} (${stmt}))`; + } + else { + /** + * 只剩下all/not all + * 翻译成键值不等条件下的not exist/exist + */ + const joinFilter = { + $expr83: { + [['all', 'not all'].includes(predicate) ? '$ne' : '$eq']: [ + { + '#attr': fk, + }, + { + '#refId': refAlia2, + '#refAttr': 'id', + } + ], + } + }; + if (!foreignKey) { + Object.assign(joinFilter, { + entity: entity2, + }); + } + const { stmt, currentNumber: ct2 } = this.translateSelectInner(subEntity, { + data: { + id: 1, + }, + filter: (0, filter_1.combineFilters)(subEntity, this.schema, [joinFilter, filter2[attr]]), + indexFrom: 0, + count: 1, + }, currentNumber, filterRefAlias, option); + currentNumber = ct2; + const PREDICATE_DICT = { + // in 和 not in已经不会命中了(优化到上面的路径中) + 'in': 'exists', + 'not in': 'not exists', + 'all': 'not exists', + 'not all': 'exists', + }; + whereText += ` ${PREDICATE_DICT[predicate]} (${stmt})`; } - const conditionalPredicate = ['all', 'not all'].includes(predicate) ? { - $not: filter2[attr], - } : filter2[attr]; - const { stmt, currentNumber: ct2 } = this.translateSelectInner(subEntity, { - data: { - id: 1, - }, - filter: (0, filter_1.combineFilters)(subEntity, this.schema, [joinFilter, conditionalPredicate]), - indexFrom: 0, - count: 1, - }, currentNumber, filterRefAlias, option); - currentNumber = ct2; - const PREDICATE_DICT = { - 'in': 'exists', - 'not in': 'not exists', - 'all': 'not exists', - 'not all': 'exists', - }; - whereText += ` ${PREDICATE_DICT[predicate]} (${stmt})`; } else { (0, assert_1.default)(attributes.hasOwnProperty(attr), `非法的属性${attr}`); diff --git a/src/sqlTranslator.ts b/src/sqlTranslator.ts index fef0c68..50f13b7 100644 --- a/src/sqlTranslator.ts +++ b/src/sqlTranslator.ts @@ -1,9 +1,11 @@ import assert from 'assert'; import SqlString from 'sqlstring'; import { assign, cloneDeep, difference, identity, intersection, keys, set } from 'lodash'; -import { Attribute, EntityDict, EXPRESSION_PREFIX, Index, OperateOption, +import { + Attribute, EntityDict, EXPRESSION_PREFIX, Index, OperateOption, Q_FullTextValue, Ref, RefOrExpression, SelectOption, StorageSchema, SubQueryPredicateMetadata, - TriggerDataAttribute, CreateAtAttribute, UpdateAtAttribute, DeleteAtAttribute, SeqAttribute, TriggerUuidAttribute } from "oak-domain/lib/types"; + TriggerDataAttribute, CreateAtAttribute, UpdateAtAttribute, DeleteAtAttribute, SeqAttribute, TriggerUuidAttribute +} from "oak-domain/lib/types"; import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain'; import { DataType } from "oak-domain/lib/types/schema/DataTypes"; import { judgeRelation } from 'oak-domain/lib/store/relation'; @@ -80,7 +82,7 @@ export abstract class SqlTranslator { attributes: [{ name: TriggerUuidAttribute, }] - }, + }, ]; // 增加外键等相关属性上的索引 @@ -788,44 +790,62 @@ export abstract class SqlTranslator { }); } const fk = foreignKey || 'entityId'; - const joinFilter = { - $expr12: { - $eq: [ - { - '#attr': fk, - }, - { - '#refId': refAlia2, - '#refAttr': 'id', - } - ], - } - }; - if (!foreignKey) { - Object.assign(joinFilter, { - entity: entity2, - }); + + // 对in和not in优化,不要用exists查询 + if (['in', 'not in'].includes(predicate)) { + const { stmt, currentNumber: ct2 } = this.translateSelectInner(subEntity, { + data: { + [fk]: 1, + }, + filter: filter2[attr] + }, currentNumber, filterRefAlias, option); + + currentNumber = ct2; + whereText += `(${refAlia2}.id ${predicate} (${stmt}))`; + } + else { + /** + * 只剩下all/not all + * 翻译成键值不等条件下的not exist/exist + */ + const joinFilter = { + $expr83: { + [['all', 'not all'].includes(predicate) ? '$ne' : '$eq']: [ + { + '#attr': fk, + }, + { + '#refId': refAlia2, + '#refAttr': 'id', + } + ], + } + }; + if (!foreignKey) { + Object.assign(joinFilter, { + entity: entity2, + }); + } + + const { stmt, currentNumber: ct2 } = this.translateSelectInner(subEntity, { + data: { + id: 1, + }, + filter: combineFilters(subEntity, this.schema, [joinFilter, filter2[attr]]), + indexFrom: 0, + count: 1, + }, currentNumber, filterRefAlias, option); + currentNumber = ct2; + + const PREDICATE_DICT = { + // in 和 not in已经不会命中了(优化到上面的路径中) + 'in': 'exists', + 'not in': 'not exists', + 'all': 'not exists', + 'not all': 'exists', + }; + whereText += ` ${PREDICATE_DICT[predicate]} (${stmt})`; } - const conditionalPredicate = ['all', 'not all'].includes(predicate) ? { - $not: filter2[attr], - } : filter2[attr]; - const { stmt, currentNumber: ct2 } = this.translateSelectInner(subEntity, { - data: { - id: 1, - }, - filter: combineFilters(subEntity, this.schema, [joinFilter, conditionalPredicate]), - indexFrom: 0, - count: 1, - }, currentNumber, filterRefAlias, option); - currentNumber = ct2; - - const PREDICATE_DICT = { - 'in': 'exists', - 'not in': 'not exists', - 'all': 'not exists', - 'not all': 'exists', - }; - whereText += ` ${PREDICATE_DICT[predicate]} (${stmt})`; } else { assert(attributes.hasOwnProperty(attr), `非法的属性${attr}`); @@ -841,7 +861,7 @@ export abstract class SqlTranslator { const predicate = Object.keys(filter2[attr])[0]; assert(predicate.startsWith('$')); // 对属性上的谓词处理 - whereText += ` (\`${alias}\`.\`${attr}\` ${this.translatePredicate(predicate, filter2[attr][predicate], type2)})`; + whereText += ` (\`${alias}\`.\`${attr}\` ${this.translatePredicate(predicate, filter2[attr][predicate], type2)})`; } } else { @@ -859,7 +879,7 @@ export abstract class SqlTranslator { }; const where = translateInner(entity, './', filter); - + return { stmt: where, currentNumber, @@ -1076,7 +1096,7 @@ export abstract class SqlTranslator { } groupByText = as; } - else if (k.startsWith('#')){ + else if (k.startsWith('#')) { let { projText: projSubText } = this.translateProjection(entity, (data as any)[k]!, aliasDict, projectionRefAlias, undefined, true); let projSubText2 = ''; if (k.startsWith('#max')) {