【问题标题】:Performance problems with joined tables连接表的性能问题
【发布时间】:2012-08-31 00:29:04
【问题描述】:

我正在使用 Grails 1.3.7 和休眠 1.3.7 和 MySQL 5.1。我有以下(简化的)域对象:

class Document {
    String externalId
    Date date
    String url
    String title

    Map metadata = new HashMap()

    def propertyMissing(String key) { return   metadata[key] }
    def propertyMissing(String key, String value) { metadata[key] = value } 
}

当我必须加载一堆这些文档以返回给客户端时,系统最终不得不为每个文档运行单独的查询以获取关联的元数据。这需要在一台合理的机器上花费数十秒来检索数百个文档及其元数据。不用说,这对于交互式使用来说太慢了。由于我的应用程序希望将所有数据加载到浏览器中以供用户操作,因此我无法将查询划分为“页面”。

目前,我正在运行的查询如下所示:

Document.executeQuery("select distinct p.document from Posting p where p.topic = :topic", [topic: topic]);

然后,此查询会导致创建一堆 Document 实例,这需要很长时间。

Hibernate缓存配置如下:

hibernate {
    cache.use_second_level_cache=true
    cache.use_query_cache=true
    cache.provider_class='net.sf.ehcache.hibernate.EhCacheProvider'
}

有问题的表格是:

mysql> describe document;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| version     | bigint(20)   | NO   |     | NULL    |                |
| date        | datetime     | YES  |     | NULL    |                |
| external_id | varchar(255) | NO   |     | NULL    |                |
| title       | longtext     | YES  |     | NULL    |                |
| url         | longtext     | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

mysql> describe document_metadata;
+--------------+---------------+------+-----+---------+-------+
| Field        | Type          | Null | Key | Default | Extra |
+--------------+---------------+------+-----+---------+-------+
| metadata     | bigint(20)    | YES  |     | NULL    |       |
| metadata_idx | varchar(255)  | YES  |     | NULL    |       |
| metadata_elt | varchar(4096) | YES  |     | NULL    |       |
+--------------+---------------+------+-----+---------+-------+

没有直接在Document 中转储元数据表和硬编码字段,我还能做些什么来提高我的代码性能?

基因

【问题讨论】:

    标签: hibernate grails


    【解决方案1】:

    也许您可以使用本机 sql 调用优化数据检索操作

    def sql = '''
      select distinct d.*, m.* 
      from 
        document d 
          join document_metadata m on m.metadata = d.id
          join post p on p.id = d.post_id
      where
        post.topic = :topic'''
    
    def query = session.createSQLQuery(sql)
    query.addEntity(com.yourdomain.Document.class)
    query.setString("topic", "grails")
    def documents = query.list()
    

    显然选择是不完整的,因为我在猜测帖子方案和关系

    【讨论】:

    • 顺便检查一下数据库中的索引。
    • 啊哈!我在 document_metadata 表中添加了一个索引,这大大改善了事情!
    • 酷。我建议您使用 p6spy 检查您的数据库连接和查询。如果您尝试使用本机 sql 调用的上述解决方案,您将看到 hibernate 生成一堆可以替换的查询
    • 谢谢!当我启用DEBUG 'org.hibernate.SQL' 跟踪时,我确实在日志中看到了一堆 SQL。根据您上述建议的索引,时间下降到 1-2 秒,即使不是很好,也可以。现在主要因素是 JSON 序列化,需要 6-8 秒。
    • 我有点不愿意在代码中引入 SQL,因为我想让它与数据库无关......
    【解决方案2】:

    您可以尝试将元数据放在关联域类中,并依赖 Grails 的默认关联延迟加载。然后,您可以更快地加载每个Document 的核心信息,并且仅在访问特定Document 时加载元数据。

    class Document {
        // Core non-Map data
    
        DocumentMetadata metadata
    
        def propertyMissing(String key) { return metadata?.data?.get(key) }
        def propertyMissing(String key, String value) { 
            if (!metadata) { metadata = new DocumentMetadata() }
            metadata.data[key] = value
        }
    }
    
    class DocumentMetadata {
        Map data = new HashMap()
    }
    

    【讨论】:

    • 不幸的是,当我需要这些文件时,我都需要它们,因为它们正在发送给客户。所以推迟元数据加载将无济于事。
    猜你喜欢
    • 1970-01-01
    • 2021-10-13
    • 2023-04-10
    • 1970-01-01
    • 2013-03-18
    • 2014-05-11
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多