#sql-server #spring-data-jpa #jpql #jpa-2.0
Вопрос:
Я новичок в базе данных SQL Server. Приведенный ниже запрос JPQL не выполняется и не выдает никаких ошибок. Просто мое приложение зависает при этом запросе. Этот код отлично работает с базой данных MySQL, но не с базой данных SQL Server (2019).
@Query(value = "SELECT R.riskType, count(distinct V.bname) FROM RiskViolation V JOIN V.job J JOIN V.risk R WHERE J.id = ?1 GROUP BY R.riskType ")
public List<Object[]> sodUserByRiskType(Long jobId);
Но когда я запускаю приведенный ниже преобразованный sql-запрос непосредственно в базе данных SQL Server, он работает нормально.
select count(distinct riskviolat0_.bname) as col_1_0_, risklog2_.risk_type as col_0_0_ from risk_violation riskviolat0_ inner join analysis_job analysisjo1_ on riskviolat0_.job_id=analysisjo1_.id inner join risk_log risklog2_ on riskviolat0_.risk_id=risklog2_.id where analysisjo1_.id=? group by risklog2_.risk_type;
Вот классы сущностей Java, которые используются в запросе JPQL:
RiskViolation.java
@Entity
@Table(name = "risk_violation")
public class RiskViolation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "job_id")
private AnalysisJob job;
private String bname;
private String riskName;
private String violations;
@Column(name = "violated", columnDefinition = "BIT", length = 1)
private boolean violated;
@Column(name = "simulation", columnDefinition = "BIT", length = 1)
private boolean simulation;
@Column(name = "mitigation_name")
private String mitigationName;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "risk_id")
private RiskLog risk;
@JsonIgnore
@OneToMany(mappedBy = "riskViolation", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<RuleViolation> ruleViolations;
}
AnalysisJob.java
@Entity
@Table(name = "analysis_job")
public class AnalysisJob {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "profile_name")
private String profileName;
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "profile_id")
@OnDelete(action = OnDeleteAction.CASCADE)
private AnalysisProfileLog profileLog;
@Column(name = "description")
private String description;
@Column(name = "status")
private String status;
@Column(name = "started_on")
private Date startedOn;
@Column(name = "completed_on")
private Date completedOn;
@Column(name = "completion_message")
private String completionMessage;
@Column(name = "percent_completed")
private float percentCompleted;
@Column(name = "run_by")
private String runBy;
@Column(name = "removed", columnDefinition = "BIT", length = 1)
private boolean removed;
@OneToMany(mappedBy = "job", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private List<JobResultData> resultData;
@Column(name = "pos_analysis", columnDefinition = "BIT", length = 1)
private boolean posAnalysis;
@Column(name = "submitted", columnDefinition = "BIT", length = 1)
private boolean submitted;
@Column(name = "position_id")
private String positionId;
}
RiskLog.java
@Entity
@Table(name = "risk_log")
public class RiskLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long jobId;
private String name;
private String riskDescription;
private String riskCondition;
private String businessProcess;
@Column(name = "business_sub_process")
private String subProc;
private String riskType;
@JsonIgnore
@OneToMany(mappedBy = "riskLog", cascade = CascadeType.ALL)
protected List<RuleLog> rules;
}
Нужно ли мне вносить какие-либо изменения в классы запросов и сущностей, чтобы это работало?
Комментарии:
1. Пожалуйста, поделитесь планом запроса через brentozar.com/pastetheplan . Чтобы получить план выполнения запроса, запустите его в SSMS, пока Jpql выполняет запрос
select qp.query_plan from sys.dm_exec_requests r cross apply sys.dm_exec_query_plan(r.plan_handle) qp where r.session_id <> @@SPID
2. Спасибо @Charlieface за ваш ответ. Я обновил свой вопрос, указав URL-адрес плана запроса внизу.
3. Попробуйте индекс
risk_violation (job_id, bname)
, вы больше ничего не можете сделать. можете ли вы загрузить «фактический» план выполнения из SSMS? Сколько строк составляет конечный результирующий набор, я не вижу из расчетного плана?4. Добавлен индекс, как вы предложили, но все тот же. Я не уверен, что правильно выполняю план запроса. На этот раз я выбрал опции «Включить фактический план выполнения» и «Включить статистику запросов в реальном времени» на панели инструментов и выполнил. Пожалуйста, ознакомьтесь с обновленным вопросом с новыми планами запросов.
5. Теперь я должен знать, как получить фактический план запроса. Дайте мне несколько минут, я добавлю это.
Ответ №1:
Это сработало после исключения класса facade между классом Java (где находится моя бизнес-логика) и репозиторием JPA (используется для выполнения запросов JPQL). Прямой вызов метода репозитория JPA из класса Java. Не уверен, почему он не работал с классом facade с SQL Server, но то же самое работало с базой данных MySQL.