go - 在go中优化SQL数据访问

标签 go go-gorm sqlx

我正在尝试将我一直在使用的 API 实现从 GORM ORM 库切换到 SQLx,以提高数据访问效率。特别是,我试图摆脱一些 SELECT N+1 问题。所以,我有一个网站有帖子的一对多关系。我正在实现的 API 返回一个站点列表作为 JSON 对象,每个站点都有一个嵌套的 posts 列表。结构看起来有点像这样

{
    "sites": [
        {
            "id": 1,
            "name": "Site #1",
            "posts" [
                {"title": "Post #1", "published": "1/2/2000", ... },
                {"title": "Post #2", "published": "1/3/2000", ... },
                ... more posts ...
            ]
        },
        {
            "id": 2,
            "name": "Site #2",
            "posts": [
                 ... post list for site #2 ...
            ]
        }
        ... more sites ...
   ]
}

这在 GORM 中很容易实现,但是当我查看正在运行的 SQL GORM 来实现它时,我意识到它正在从列表中的每个站点的帖子中进行选择。所以我试图像这样使用 SQL 来避免 N+1 问题。

SELECT s.id, s.name, p.title, p.published 
FROM sites as s, posts as p 
WHERE p.site_id = s.id

这让我在单个查询中获得了我需要的所有数据。但是我对如何将所有这些扫描到站点结构列表中有些困惑。在 GORM 中,我定义了以下结构(为简洁起见进行了简化)

type struct Post {
    Id        uint      `json:"-"`
    Title     string
    Published time.Time
    SiteId    uint      `json:"-"`
    Site      Site      `json:"-"`
}

type struct Site {
    Id   uint
    Name string
}

然后我会做类似的事情

var sites []Site
result := db.Preload('Posts').Find(&sites)
if result.Error != nil {
    ... error handling ...
} else {
   operate on sites here
}

所以问题是,如何使用 SQLx 将我的新 SQL 扫描到结构 slice 中,从而产生与 GORM 生成的数据结构类似的数据结构?我不介意编写自己的扫描器,但我仍然希望能够使用 SQLx Select()Get() 方法。我需要做什么才能完成这项工作?

var sites []Site
err := db.Select(query, &sites) // where query is SQL from above

编辑:似乎如果我执行我在这个问题中给出的确切代码,GORM 实际上不会执行 N+1 选择,它会运行两个查询,一个用于站点的简单 SELECT 和一个SELECT ... WHERE ... IN ... for posts 然后整理两个结果集。不过,我仍然想知道如何在 SQLx 中执行此操作。

最佳答案

这可能不是答案,但对于评论来说太长了。

如果您仍在使用 GORM,则可以创建自定义 SQL。 请参阅文档:http://jinzhu.me/gorm/advanced.html#sql-builder

对你来说可能是这样的:

// Scan

type struct Post {
    Id        uint      `json:"-"`
    Title     string
    SiteId    uint      `json:"-"`
    Site      Site      `json:"-"`
}

var result Post

db.Raw("
SELECT s.id, s.name, p.title, p.published 
FROM sites as s, posts as p 
WHERE p.site_id = s.id").Scan(&result)

关于go - 在go中优化SQL数据访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42815331/

相关文章:

go - 通过 go exec.cmd 运行 SCP

postgresql - 如何使用Gorm向现有列添加默认值

mysql - GORM 中的多个一对多关系

go - 在 golang 项目中查询 sqlx 后数据库连接仍在使用中

sql - 未传入某些参数时如何进行SQL查询过滤?

json - Go中泛型的解决方案

go - golang 中的内存泄漏

go - "unknown tls.Config field"错误是什么意思?

go - 如何从另一个文件或包导入 gorm db 连接

sql - 将查询移至处理程序获取 "undefined: db"(golang)