我有一个页面,该页面以分页的方式在网格中显示一些记录。我有表my_table
和链接到它的实体MyTable
:
@SuppressWarnings("serial")
@Entity
@Table(name="my_table")
@Inheritance(strategy=InheritanceType.JOINED)
public class MyTable extends BaseEntity implements Auditable, Serializable {
//...
private Integer myAttribute; //This does not exist in the table
//...
@Formula(value = "(myFunction(attr1, attr2))")
public Integer getMyAttribute() {
return myAttribute;
}
public void setMyAttribute(Integer myAttribute) {
this.myAttribute = myAttribute;
}
//...
}
当我打算通过“普通”字段进行查询时,一切工作都很好,但是当我尝试通过myAttribute
进行过滤时,例如:
queryInput.addAndCriterion(Restrictions.eq("myAttribute", v));
例如,v
是值为{123的Integer
,搜索将超时。如果我直接在MySQL中运行存储的函数,那么它将立即执行。我认为这段代码会在每个项目上发送一个单独的请求,这可以解释问题。有没有一种方法可以确保我可以以一种高性能的方式对存储的函数进行过滤(也许对存储函数的调用将在查询中生成)?我需要定义一个标准,该标准指定对于每个记录,都需要调用某个存储的函数,并传递attr1
和attr2
,它们是记录的字段?
答案 0 :(得分:1)
如以下评论中所述,此答案不能解决对Hibernate进行故障排除的问题,但OP还是喜欢它。
答案在后面...
查询任何函数,存储函数或内置函数始终是表扫描。
例如,即使存在索引,create_date
也无法使用索引:
SELECT * FROM MyTable WHERE MONTH(create_date) = 2
每当您使用索引列作为函数的参数时,都是如此。
MySQL 5.7和更高版本的解决方法是对该表达式使用generated column,然后为生成的列建立索引。
ALTER TABLE MyTable
ADD COLUMN created_month INT AS (MONTH(create_date)),
ADD INDEX (created_month);
这样做之后,您可以查询created_month = 2
,甚至可以查询原始表达式MONTH(create_date) = 2
,它将使用索引。
不幸的是,您只能将此功能与内置的MySQL函数一起使用。
https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html说:
生成的列表达式必须遵守以下规则。如果表达式包含不允许的构造,则会发生错误。
- 不允许使用存储的函数和用户定义的函数。
另一种解决方案是让您创建一个新的具体列来存储存储函数的结果,假设该值是根据其参数确定的,并且不依赖于其他表中的数据状态。
ALTER TABLE MyTable
ADD COLUMN myAttribute INT,
ADD INDEX (myAttribute);
CREATE TRIGGER att_ins BEFORE INSERT ON MyTable
FOR EACH ROW SET NEW.myAttribute = MyFunction(NEW.attr1, NEW.attr2);
CREATE TRIGGER att_upd BEFORE UPDATE ON MyTable
FOR EACH ROW SET NEW.myAttribute = MyFunction(NEW.attr1, NEW.attr2);
然后,您将查询新列而不是表达式。
有点麻烦,但这是针对存储函数的结果进行索引查找的唯一方法。