首页 文章

在go中优化SQL数据访问

提问于
浏览
2

我正在尝试将我一直在使用的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正在运行来实现它,我意识到它正在为列表中的每个站点的帖子做一个SELECT . 所以我试图像这样使用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扫描到一个结构片中,从而产生与GORM生成的类似数据结构?我不介意编写自己的扫描仪,但我仍然希望能够使用SQLx Select()Get() 方法 . 我需要做些什么来完成这项工作?

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

Edit: 似乎如果我在这个问题中做了确切的代码,GORM实际上并没有做N 1选择,它运行两个查询,一个简单的SELECT用于站点,一个SELECT ... WHERE ... IN ...对于帖子,然后整理两个结果集 . 我仍然想知道如何在SQLx中执行此操作 .

1 回答

  • 0

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

    如果您仍在使用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)
    

相关问题