优化 Grails 查询

Posted

技术标签:

【中文标题】优化 Grails 查询【英文标题】:Optimize Grails Queries 【发布时间】:2015-05-20 10:24:37 【问题描述】:

我正在尝试优化我的 grails 应用程序的速度。 我有这个:

Catalog a= Catalog.findByName('a');
Element b= Element.findByCatalogAndNumber(a,2);

这样我可以找到b。

但我想我可以使用这样的东西:

Element b= Element.createCriteria().get
       catalog
          eq("name",'a')
       
       eq("number",2)

但我不确定它是否会减少对数据库的查询,或者我只是在自欺欺人并创建更大的文件并通过这样做降低我的应用程序的速度。

有什么想法吗?

【问题讨论】:

优化而不测量是浪费时间 如果有办法知道每个版本运行了多少数据库查询,那就太酷了。更酷 - 查看实际 SQL 的能力。哦,好吧,也许有一天…… @BurtBeckwith "Someday" is today ...要么通过打开"DB语句日志"功能,否则你可以turn it on in Grails 酷。你激励我回到过去写this blog post和this update 【参考方案1】:

我已经比较了您查询的三个版本,使用

Grails 2.4.4,Grails 应用程序中缓存的默认设置 PostgreSQL 8.4,SQL 语句日志记录已开启以统计/查看 SQL 查询。

第一个版本在 Grails 域类上使用 两次调用

def query1() 
  Catalog a = Catalog.findByName('a');
  log.info(a)

  Element b = Element.findByCatalogAndPos(a, 2);
  log.info(b)

  render(b.toString())

第二个使用criteria

def query2() 
  Element b = Element.createCriteria().get 
    catalog 
      eq("name", "a")
    
    eq("pos", 2)
  

  render(b.toString())

最后一个使用 where 查询

def query3() 
  def query = Element.where 
    catalog.name == "a" && pos == 2
  

  Element b = query.get()

  render(b.toString())

第一个导致 两个 SQL 查询,其他的只会发送 一个查询 到数据库(使用从 ElementCatalog 的内连接)。

至于可读性/表现力,请选择第3个版本:它在一行中表达了您的意图,并且是最紧凑的版本。

至于性能,选择第 2 版或第 3 版。在高负载、许多并发用户/请求的情况下,查询的数量确实很重要。这可能不是所有应用程序的问题。

无论如何,我总是选择第 3 版的表现力;如果查询条件随着时间的推移变得更加复杂,它会扩展。


更新

第一版使用的SQL语句:

select this_.id as id1_1_0_, this_.version as version2_1_0_, this_.date_created as date_cre3_1_0_, this_.last_updated as last_upd4_1_0_, this_.name as name5_1_0_, this_.remark as remark6_1_0_ 
  from catalog this_ 
  where this_.name=$1 limit $2
Parameter: $1 = 'a', $2 = '1'

select this_.id as id1_2_0_, this_.version as version2_2_0_, this_.catalog_id as catalog_3_2_0_, this_.date_created as date_cre4_2_0_, this_.last_updated as last_upd5_2_0_, this_.pos as pos6_2_0_, this_.remark as remark7_2_0_ 
  from element this_ 
  where this_.catalog_id=$1 and this_.pos=$2 limit $3
Parameter: $1 = '10', $2 = '2', $3 = '1'

第二版和第三版的SQL语句:

select this_.id as id1_2_1_, this_.version as version2_2_1_, this_.catalog_id as catalog_3_2_1_, this_.date_created as date_cre4_2_1_, this_.last_updated as last_upd5_2_1_, this_.pos as pos6_2_1_, this_.remark as remark7_2_1_, catalog_al1_.id as id1_1_0_, catalog_al1_.version as version2_1_0_, catalog_al1_.date_created as date_cre3_1_0_, catalog_al1_.last_updated as last_upd4_1_0_, catalog_al1_.name as name5_1_0_, catalog_al1_.remark as remark6_1_0_ 
  from element this_ inner join catalog catalog_al1_ 
    on this_.catalog_id=catalog_al1_.id 
    where (catalog_al1_.name=$1) and this_.pos=$2
Parameter: $1 = 'a', $2 = '2'

【讨论】:

统计查询只是第一步。您必须查看总时间、查询的复杂性(例如,您可能在一个查询中完成,但它需要大量的数据库服务器活动)、传输的数据量(例如,您选择的数据过多被丢弃)等。 @BurtBeckwith 我已经添加了 SQL 语句。在这种情况下,会提取相同的列,并且所有查询都很简单。但是两次查询总是意味着两次完整的数据库往返,并且在高负载下,网络带宽可能是瓶颈 - 我在生产系统上看到过这个问题:大量非常简单的 SQL 语句会扼杀性能。另一方面,SQL 数据库对涉及许多连接/条件的非常复杂的查询非常满意。所以“如果你可以在一条 SQL 语句中完成,那么一定要在一条 SQL 语句中完成”(引自“Ask Tom”)。 假设一个查询总是优于返回相同结果的两个不同查询,这是相当幼稚的。 @BurtBeckwith 那么我们同意不同意。是的,在某些情况下可能无法将不相关的查询合并为一个,但在过去两年使用 Oracle 和 PostgreSQL 进行 SQL 性能调整期间,我没有看到可以组合的独立查询在压力测试中表现更好。跨度>

以上是关于优化 Grails 查询的主要内容,如果未能解决你的问题,请参考以下文章

Grails 命名查询

Grails 安全问题和搜索引擎优化

grails的criteria和hql查询

Grails 查询不使用 GORM

将 SQL 查询转换为 Grails

Grails 命名查询