MySQL行子查询语句有关问题
程序员文章站
2022-05-20 10:26:01
...
MySQL行子查询语句问题 大家好,在项目中碰到如下问题: hibernate 映射表的时候使用联合主键 例子如下: 商品表:Item,主键为联合主键ItemId 代码如下 public class ItemId{ @column Long itemId; @column Long userId;}@Table(...)public class Item{ @Id
MySQL行子查询语句问题大家好,在项目中碰到如下问题:
hibernate 映射表的时候使用联合主键
例子如下:
商品表:Item,主键为联合主键ItemId
代码如下
public class ItemId{ @column Long itemId; @column Long userId; } @Table(...) public class Item{ @Id ItemId id; @column Date createDate; @column boolean deleted; ... }
三个手动创建索引如下:
itemId 主键索引
userId 主键索引
itemId, userId 联合索引
数据库表为InnerDB
更新一条语句示例如下:
public void softDeleteItem(long itemId, long userId){ session.createQuery("update Item set deleted = :deleted WHERE id=:id") .setParameter("deleted", 1) .setParameter("id", new ItemId(itemId, userId)) .executeQuery(); }
通过上面的更新语句hibernate产生如下SQL语句
update item set delete=? where (itemId, roleId) = (?, ?)
在后台查询这条sql语句非常耗时,在item表数据量达到百万级级的时候好使就需要2~3秒
通过查询返回的详细参数可以看到Mysql做全表查询了,而且锁表了,并没有使用索引。
之后为了解决线上问题,就做出更改如下
public void softDeleteItem(long itemId, long userId){ session.createQuery("update Item set deleted = :deleted WHERE id.itemId=:itemId AND id.userId = :userId") .setParameter("deleted", 1) .setParameter("itemId", itemId) .setParameter("userId", userId) .executeQuery(); }
hibernate生成的语句如下:
update item set delete=? where itemId = ? and roleId=?
效率立即上去了,使用了索引,更新只需要毫秒级的时间。
故,两个问题:
1. hibernate为什么会生成
update item set delete=? where (itemId, roleId) = (?, ?)
而不是
update item set delete=? where itemId = ? and roleId = ?
2. 上面两条sql语句在mysql执行的效率为什么不一样 ?
何解?
备注:
Mysql官方文档对行子查询的说明如下:
引用对于本点的讨论属于标量或列子查询,即返回一个单一值或一列值的子查询。行子查询是一个能返回一个单一行的子查询变量,因此可以返回一个以上的列值。以下是两个例子:
SELECT * FROM t1 WHERE (1,2) = (SELECT column1, column2 FROM t2);
SELECT * FROM t1 WHERE ROW(1,2) = (SELECT column1, column2 FROM t2);
如果在表t2的一个行中,column1=1并且column2=2,则查询结果均为TRUE。
表达式(1,2)和ROW(1,2)有时被称为行构造符。两者是等同的,在其它的语境中,也是合法的。例如,以下两个语句在语义上是等同的(但是目前只有第二个语句可以被优化):
SELECT * FROM t1 WHERE (column1,column2) = (1,1);
SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;
行构造符通常用于与对能返回两个或两个以上列的子查询进行比较。例如,以下查询可以答复请求,“在表t1中查找同时也存在于表t2中的所有的行”:
SELECT column1,column2,column3
FROM t1
WHERE (column1,column2,column3) IN
(SELECT column1,column2,column3 FROM t2);