Добрый день.
Очередной вопрос при миграции с 1.1.3 на 2.7.4.
После миграции, возникла проблема с производительностью. Запрос через rest аддон, который выполнялся десятки миллисекунд, стал выполняться более секунды.

Сущности:
@JmixEntity
@Table(name = "MED_WORKPLACE", indexes = {
@Index(name = "IDX_MED_WORKPLACE_CODE", columnList = "CODE"),
@Index(name = "IDX_MED_WORKPLACE_POSITION_CODE", columnList = "POSITION_CODE"),
@Index(name = "IDX_MED_WORKPLACE_MAIN_DEPARTMENT_CODE", columnList = "MAIN_DEPARTMENT_CODE"),
@Index(name = "IDX_MED_WORKPLACE_ORGANIZATION_CODE", columnList = "ORGANIZATION_CODE"),
@Index(name = "IDX_MED_WORKPLACE_CONDITION_CLASS", columnList = "CONDITION_CLASS_ID"),
@Index(name = "IDX_MED_WORKPLACE_WORK_CONDITION_TYPE", columnList = "WORK_CONDITION_TYPE_ID"),
@Index(name = "IDX_MED_WORKPLACE_WORK_CONDITION_SUBTYPE", columnList = "WORK_CONDITION_SUBTYPE_ID"),
@Index(name = "IDX_MED_WORKPLACE_POSITION", columnList = "POSITION_ID")
})
@Entity(name = "med_Workplace")
@Getter
@Setter
public class Workplace extends BaseEntity implements HasPeriod, HasOrgStructureProperties {
@InstanceName
@Column(name = "CODE", nullable = false)
@NotNull(message = "{msg://ru.digitalatom.medicalexamination.entity/Workplace.code.validation.NotNull}")
private String code;
@Column(name = "HR_CODES", length = 1024)
private String hrCodes;
@Column(name = "NAME")
private String name;
@JoinColumn(name = "CONDITION_CLASS_ID")
@ManyToOne(fetch = FetchType.LAZY)
private ConditionClass conditionClass;
@Column(name = "WORK_CONDITION_CARD_NUMBER")
private String workConditionCardNumber;
@Column(name = "WORK_CONDITION_DATE")
private LocalDate workConditionDate;
@JoinColumn(name = "WORK_CONDITION_TYPE_ID")
@ManyToOne(fetch = FetchType.LAZY)
private WorkConditionType workConditionType;
@JoinColumn(name = "WORK_CONDITION_SUBTYPE_ID")
@ManyToOne(fetch = FetchType.LAZY)
private WorkConditionSubtype workConditionSubtype;
@NotNull(message = "{msg://ru.digitalatom.medicalexamination.entity.workplace/Workplace.positionCode.validation.NotNull}")
@Column(name = "POSITION_CODE", nullable = false)
private String positionCode;
@Column(name = "POSITION_NAME")
private String positionName;
@NotNull(message = "{msg://ru.digitalatom.medicalexamination.entity.workplace/Workplace.departmentCode.validation.NotNull}")
@Column(name = "DEPARTMENT_CODE", nullable = false)
private String departmentCode;
@Column(name = "DEPARTMENT_NAME")
private String departmentName;
@NotNull(message = "{msg://ru.digitalatom.medicalexamination.entity.workplace/Workplace.mainDepartmentCode.validation.NotNull}")
@Column(name = "MAIN_DEPARTMENT_CODE", nullable = false)
private String mainDepartmentCode;
@Column(name = "MAIN_DEPARTMENT_NAME")
private String mainDepartmentName;
@Column(name = "ORGANIZATION_CODE")
private String organizationCode;
@Column(name = "ORGANIZATION_NAME")
private String organizationName;
@JoinColumn(name = "POSITION_ID")
@ManyToOne(fetch = FetchType.LAZY)
private Position position;
@EmbeddedParameters(nullAllowed = false)
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "since", column = @Column(name = "PERIOD_SINCE")),
@AttributeOverride(name = "until", column = @Column(name = "PERIOD_UNTIL"))
})
private Period period;
@OrderBy("period.since")
@OneToMany(mappedBy = "workplace")
private List<WorkplaceFactor> factors;
@OneToMany(mappedBy = "workplace")
private List<EmployeeWorkplace> employees;
@Override
public Period getPeriod() {
return period;
}
@Override
public void setPeriod(Period period) {
this.period = period;
}
public List<WorkplaceFactor> getActualFactors(LocalDate date) {
return factors.stream()
.filter(workplaceFactor -> workplaceFactor.getPeriod().isIncluded(date))
.toList();
}
public List<EmployeeWorkplace> getActualEmployees(LocalDate date) {
return employees.stream()
.filter(employeeWorkplace -> employeeWorkplace.getPeriod().isIncluded(date))
.toList();
}
}
@JmixEntity
@Table(name = "MED_WORKPLACE_FACTOR", indexes = {
@Index(name = "IDX_MED_WORKPLACE_FACTOR_WORKPLACE", columnList = "WORKPLACE_ID"),
@Index(name = "IDX_MED_WORKPLACE_FACTOR_FACTOR", columnList = "FACTOR_ID")
})
@Entity(name = "med_WorkplaceFactor")
@Getter
@Setter
public class WorkplaceFactor extends BaseEntity implements HasHarmfulFactor, HasPeriod {
@NotNull(message = "{msg://ru.digitalatom.medicalexamination.entity.factor/WorkplaceFactor.workplace.validation.NotNull}")
@JoinColumn(name = "WORKPLACE_ID", nullable = false)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private Workplace workplace;
@JoinColumn(name = "FACTOR_ID", nullable = false)
@NotNull(message = "{msg://ru.digitalatom.medicalexamination.entity.workplace/WorkplaceFactor.factor.validation.NotNull}")
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private HarmfulFactor factor;
@EmbeddedParameters(nullAllowed = false)
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "since", column = @Column(name = "PERIOD_SINCE", nullable = false)),
@AttributeOverride(name = "until", column = @Column(name = "PERIOD_UNTIL"))
})
private Period period;
@Override
public Period getPeriod() {
return period;
}
@Override
public void setPeriod(Period period) {
this.period = period;
}
@Override
public HarmfulFactor getFactor() {
return factor;
}
@InstanceName
@DependsOnProperties({"id"})
public String getInstanceName(MetadataTools metadataTools) {
return metadataTools.format(getId());
}
}
@JmixEntity
@Table(name = "MED_HARMFUL_FACTOR", indexes = {
@Index(name = "IDX_MED_HARMFUL_FACTOR_GROUP", columnList = "GROUP_ID"),
@Index(name = "IDX_MED_HARMFUL_FACTOR_TYPE", columnList = "TYPE_ID"),
@Index(name = "IDX_MED_HARMFUL_FACTOR_RECORD_TYPE", columnList = "RECORD_TYPE_ID")
})
@Entity(name = "med_HarmfulFactor")
@Getter
@Setter
public class HarmfulFactor extends BaseEntity implements HasPeriod {
@JoinColumn(name = "GROUP_ID")
@ManyToOne(fetch = FetchType.LAZY)
private FactorGroup group;
@JoinColumn(name = "TYPE_ID")
@ManyToOne(fetch = FetchType.LAZY)
private FactorType type;
@JoinColumn(name = "RECORD_TYPE_ID")
@ManyToOne(fetch = FetchType.LAZY)
private FactorRecordType recordType;
@Column(name = "CODE")
private String code;
@InstanceName
@Column(name = "NAME", nullable = false, length = 1024)
@NotNull(message = "{msg://ru.digitalatom.medicalexamination.entity.factor/HarmfulFactor.name.validation.NotNull}")
private String name;
@Column(name = "SHORT_NAME", length = 1024)
private String shortName;
@OnDeleteInverse(DeletePolicy.DENY)
@JoinColumn(name = "PERIODICITY_ID")
@ManyToOne(fetch = FetchType.LAZY)
private Periodicity periodicity;
@EmbeddedParameters(nullAllowed = false)
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "since", column = @Column(name = "PERIOD_SINCE")),
@AttributeOverride(name = "until", column = @Column(name = "PERIOD_UNTIL"))
})
private Period period;
@OnDeleteInverse(DeletePolicy.UNLINK)
@JoinTable(name = "MED_HARMFUL_FACTOR_EXAMINATION_LINK",
joinColumns = @JoinColumn(name = "HARMFUL_FACTOR_ID", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(name = "EXAMINATION_ID", referencedColumnName = "ID"))
@OrderBy("name")
@ManyToMany
private List<Examination> examinations;
@OnDeleteInverse(DeletePolicy.UNLINK)
@JoinTable(name = "MED_HARMFUL_FACTOR_ADDITIONAL_EXAMINATION_LINK",
joinColumns = @JoinColumn(name = "HARMFUL_FACTOR_ID", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(name = "ADDITIONAL_EXAMINATION_ID", referencedColumnName = "ID"))
@ManyToMany
private List<AdditionalExamination> additional;
@Override
public Period getPeriod() {
return period;
}
@Override
public void setPeriod(Period period) {
this.period = period;
}
}
Фетч-план:
<fetchPlan name="workplace-full-rest"
class="ru.digitalatom.medicalexamination.entity.workplace.Workplace"
extends="_base">
<property name="factors" fetchPlan="_base">
<property name="factor" fetchPlan="_base"/>
</property>
</fetchPlan>
По логу видно, что имеется проблема N+1 (которой кстати не было в 1.1.3, запрос выполнялся через IN), но даже при этом запросы выполняются быстро, потом видимо идёт сериализация, которая и занимает львиную долю времени.
2026-02-19T16:14:35.384+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 2009942312> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, DEPARTMENT_CODE, DEPARTMENT_NAME, HR_CODES, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, MAIN_DEPARTMENT_CODE, MAIN_DEPARTMENT_NAME, NAME, ORGANIZATION_CODE, ORGANIZATION_NAME, POSITION_CODE, POSITION_NAME, VERSION, WORK_CONDITION_CARD_NUMBER, WORK_CONDITION_DATE, PERIOD_SINCE, PERIOD_UNTIL, CONDITION_CLASS_ID, POSITION_ID, WORK_CONDITION_SUBTYPE_ID, WORK_CONDITION_TYPE_ID FROM MED_WORKPLACE WHERE ((ID = ?) AND (DELETED_DATE IS NULL))
bind => [7a727958-93b3-e248-883e-a145a6e07d2b]
2026-02-19T16:14:35.385+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 2009942312> [1 ms] spent
2026-02-19T16:14:35.386+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 419678543> SELECT ID, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, VERSION, PERIOD_SINCE, PERIOD_UNTIL, FACTOR_ID, WORKPLACE_ID FROM MED_WORKPLACE_FACTOR WHERE ((WORKPLACE_ID = ?) AND (DELETED_DATE IS NULL)) ORDER BY PERIOD_SINCE ASC
bind => [7a727958-93b3-e248-883e-a145a6e07d2b]
2026-02-19T16:14:35.387+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 419678543> [1 ms] spent
2026-02-19T16:14:35.389+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 265832580> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [5935b891-9d04-421a-9e7d-bcafb2f293e2]
2026-02-19T16:14:35.390+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 265832580> [1 ms] spent
2026-02-19T16:14:35.391+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 576886058> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [c4b74469-38e1-4172-b24b-a1cf5922e0b1]
2026-02-19T16:14:35.391+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 576886058> [0 ms] spent
2026-02-19T16:14:35.391+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 879602484> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [6457ad74-3d9b-10e3-c562-1a1fa5c44077]
2026-02-19T16:14:35.393+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 879602484> [2 ms] spent
2026-02-19T16:14:35.393+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 186806203> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [ba3d886f-a08b-4552-96f1-0d923c7698ba]
2026-02-19T16:14:35.394+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 186806203> [1 ms] spent
2026-02-19T16:14:35.396+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 1152572432> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [462742f7-3777-6ff2-535b-bccae0e50d82]
2026-02-19T16:14:35.397+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 1152572432> [1 ms] spent
2026-02-19T16:14:35.398+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 1540453175> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [4d17664e-e48a-40c1-9f96-eaa212acaa8b]
2026-02-19T16:14:35.398+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 1540453175> [0 ms] spent
2026-02-19T16:14:35.399+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 790788988> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [2ad1c5d4-abc7-41b8-827a-d1b8e1f1513a]
2026-02-19T16:14:35.400+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 790788988> [1 ms] spent
2026-02-19T16:14:35.400+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 475581716> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [c9553cf0-5666-45df-8720-c503a30ee167]
2026-02-19T16:14:35.401+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 475581716> [1 ms] spent
2026-02-19T16:14:35.403+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 472643597> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [4dd89a0f-ed7b-001b-7f35-a052f274058a]
2026-02-19T16:14:35.404+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 472643597> [1 ms] spent
2026-02-19T16:14:35.404+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 888594786> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [bcce02e5-ccd9-4a45-bda2-32a309f8111b]
2026-02-19T16:14:35.405+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 888594786> [1 ms] spent
2026-02-19T16:14:35.405+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 47181998> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [b95e0fd1-110b-92b1-b25c-90395d0bfe0a]
2026-02-19T16:14:35.405+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 47181998> [0 ms] spent
2026-02-19T16:14:35.406+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 37111297> SELECT ID, CODE, CREATED_BY, CREATED_DATE, DELETED_BY, DELETED_DATE, LAST_MODIFIED_BY, LAST_MODIFIED_DATE, NAME, SHORT_NAME, VERSION, PERIOD_SINCE, PERIOD_UNTIL, GROUP_ID, PERIODICITY_ID, RECORD_TYPE_ID, TYPE_ID FROM MED_HARMFUL_FACTOR WHERE ((ID = ?) AND (0=0))
bind => [e1d90825-70d2-4f8f-98c8-018793690474]
2026-02-19T16:14:35.406+03:00 DEBUG 5568 --- [nio-8081-exec-8] eclipselink.logging.sql : <t 2110891703, conn 37111297> [0 ms] spent