这是一个记录良好的模式吗?

时间:2011-07-07 18:27:31

标签: sql database optimization design-patterns union-all

我试图找出以下是一个记录良好的模式(或反模式),以减少应用程序延迟。我已经尝试过这种技术,但从表面上看这似乎可以节省20%的延迟。我想知道是否有任何副作用,我应该知道

上下文:

你有一个方法/函数/过程对数据库进行多次SELECT调用,你需要优化它。

让我们说你的方法的流程是:

  getDBConnection()  
  execute("Select a,b from tableA");  
  bind a with varA 
  bind b with varB  
  ---SOME Business Logic-----  
  execute("Select c,d from tableB");  
  bind c with varC  
  bind d with varD   
  ---SOME more Business Logic-----  
  execute("Select e,f from tableC");  
  bind e with varE  
  bind f with varF  
  ---SOME more Business Logic-----  
  releaseConnection()

解决方案: 使用Union ALL对数据库进行单次调用

 getDBConnection()
 execute("Select a,b,'sqlA' from tableA"+  
 " UNION ALL "+  
 " Select c,d,'sqlB' from tableB"+  
 " UNION ALL "+
 "Select e,f,'sqlC' from tableC");  
 bind a,b where records have "sqlA"   
 bind c,d where records have "sqlB"
 bind e,f where records have "sqlC"  
 releaseConnection()  
 --------Do all Business Logic here-----

2 个答案:

答案 0 :(得分:6)

使用union会限制查询的“形状”。它们基本上必须以相同的顺序返回相同数量和(兼容)类型的列。

更好的方法是在单个命令中使用多个查询,然后处理多个结果集:

execute("Select a,b from tableA;"+
  "Select c,d from tableB;"+
  "Select e,f from tableC");

或者可以创建一个运行这些查询的专用存储过程。

除此之外,这种优化技术可以将不相关的操作混为一谈,这将限制以后各个操作的可重用性。您可能需要考虑更好地分离这些操作的设计,并使用某种QueryManager来首先收集它们,然后将它们全部一起运行。

答案 1 :(得分:1)

将所有内容推到一起可能会掩盖真正的问题:您知道延迟的来源吗?

如果多次调用这些查询,您可能会在编译阶段花费大量时间。如果表在应用程序的生命周期内没有太大的变化,那么使用预准备语句可能会有所帮助:

conn = connect_to_db()
pstmt = conn.prepare('select ...')
...
pstmt.bind(parameters) // if necessary
pstmt.execute()

如果延迟不是来自编译,则可能是执行 - 您提供的查询是简单的选择,但任何更复杂的查询都可能需要检查解释计划。

如果你的dbms和你的表的结构允许,那么一些重组也可能有助于减少需要完成多少查询:你能否将select语句与连接而不是联合组合?你可以将表与分区合并吗?

这就是一堆一般性的想法。为了回答你的实际问题,我没有看到以前使用过的方法,但我不会让恶名成为唯一的决定因素。正如之前的海报所指出的那样,您可能会牺牲代码的可重用性。最后,随着表的数量的增加,这种方法的扩展性不会很好:你仍然需要在应用程序代码中查找哪些行有“sqlA”,“sqlB”等。