我在MySQL中有一个名为Orders的表,其中包含订单的详细信息。 我有另一个名为OrderItems的表。
OrderItems包含以下字段:OrderID,ProductID,Qty
现在在java中我有一个名为Order的类,它有一个List。
假设我想从我的数据库中获取所有订单,包括每个订单的OrderItems。但我想以最有效的方式做到这一点。
我目前的解决方案(我认为可能很慢)是:
循环遍历行的ResultSet并定义OrderDetails,每次我遍历一行时,我执行另一个PreparedStatement并使用当前Order的OrderID循环OrderItems。然后我在列表中添加项目并转到下一个订单。
但我可以想象这个过程将非常缓慢且资源密集。在进行标准化(3NF)时,最有效的方法是什么。
根据要求,我已经写了一个我的解决方案的例子
public List<Order> getAllOrders() throws SQLException{
ArrayList<Order> list = new ArrayList<Order>(0);
ResultSet x = qry("Select * from Orders");
while(x.next()){
Order r = new Order();
//setOrderDetails
r.setItems(getOrderItems(r));
}
return list;
}
public ArrayList<OrderItem> getOrderItems(Order r) throws SQLException {
ArrayList<OrderItem> list = new ArrayList<OrderItem>(0);
ResultSet x = qry("Select * from OrderItems where OrderID = "+r.getId()+";");
while(x.next()){
OrderItem newItem = new OrderItem();
newItem.setOrderId(r.getId());
newItem.setProduct(null); //Uses some kind of inner join to get the product details
newItem.setPrice(newItem.getProduct().getPrice());
newItem.setQuantity(x.getInt(4));
}
return list;
}
好的,我已经按照你们的建议......平均花费超过20秒How it looks
日志:
Time took to connect: 3270ms
Start CustomerService: 38ms
Start ProductService: 1ms
Start OrderService: 2ms
Customer Size: 4
Qry All Customers: 149ms
Products Size: 420
Qry All Products: 391ms
Order already contains: ENALAPRILMALEAAT HCT 20/12,5MG ACTAVIS BV
Add Order(28 items) Took: 2350ms
Qry all orders(27 orders) took: 7929ms
这真的很难......有时可能需要20秒。(要求所有订单)
这是另一个仍然需要30秒才能只需要28个订单...(所有每个最多28个项目
Time took to connect: 7117ms Start CustomerService: 35ms Start ProductService: 1ms Start OrderService: 1ms Customer Size: 4 Qry All Customers: 126ms Products Size: 420 Qry All Products: 700ms Add Order(6 items) Took: 2117ms Qry all orders(28 orders) took: 30150ms
答案 0 :(得分:0)
在我看来,您的数据(每周有4个新订单的600种产品)并不是那么庞大,您现在就需要进行性能优化。但如果你应该,你可以优化它,如果你的代码如下所示(我刚刚修改了你的代码):
public List<Order> getAllOrders() throws SQLException{
ArrayList<Order> list = new ArrayList<Order>(0);
PreparedStatement ps = connection.prepareStatement("Select * from OrderItems where OrderID = ?"); // (1)
ResultSet x = qry("Select * from Orders");
while(x.next()){
Order r = new Order();
//setOrderDetails
r.setItems(getOrderItems(r, ps));
list.add(r);
}
return list;
}
public ArrayList<OrderItem> getOrderItems(Order r, PreparedStatement ps) throws SQLException {
ArrayList<OrderItem> list = new ArrayList<OrderItem>(0);
ps.setString(1, r.getId()); // (2)
ResultSet x = ps.executeQuery(); // (3)
while(x.next()){
OrderItem newItem = new OrderItem();
newItem.setOrderId(r.getId());
newItem.setProduct(null); //Uses some kind of inner join to get the product details
newItem.setPrice(newItem.getProduct().getPrice());
newItem.setQuantity(x.getInt(4));
}
return list;
}
现在发生了什么变化?
准备好的语句现在不在循环中,它将被重用(参见change(1))。与之前准备的查询相比,这应该会带来巨大的性能提升,因为查询只会被解析一次。
在(2)中,将为当前订单设置参数。
在(3)中将执行查询。
答案 1 :(得分:0)
这是一个较晚的答案,但对于查询时间较慢的用户而言。 尝试将自动提交设置为false。当您在代码中实际创建连接时, 做connection.setAutoCommit(false);然后在代码中放入connection.commit();执行查询后。我在尝试插入150000个对象时遇到了同样的问题,这大约花费了23分钟。将auto commit设置为false然后提交后,我花了大约27秒钟。希望对您有所帮助。
这是提交的代码示例:
@Override
public void create(Member member) {
try {
Connection connection = localConnection.getConnection();
PreparedStatement sqlInsert = connection.prepareStatement(memberDaoUtil.create());
sqlInsert.setString(1, member.getMemberId());
sqlInsert.setString(2, member.getName());
sqlInsert.setString(3, member.getPersonalNumber());
sqlInsert.setString(4, member.getUsername());
sqlInsert.setString(5, member.getPassword());
sqlInsert.setInt(6, member.getNumOfBoats());
sqlInsert.setBoolean(7, member.isAdmin());
sqlInsert.executeUpdate();
connection.commit();
sqlInsert.close();
} catch(SQLException ex) {
ex.printStackTrace();
}
}
然后也在连接的构造函数中:
private LocalConnection(Connection connection) {
this.connection = connection;
try {
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
您会看到connection.setAutoCommit(false); 您可以在下面的链接中阅读其功能。 Understand Auto Commit