我正在尝试将我一直在使用的 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/