2017-03-15 52 views
2

我試圖將我一直在從GORM ORM庫開發的API實現切換到SQLx,以使數據訪問更高效。特別是,我試圖擺脫一些SELECT N + 1問題。所以,我有一個網站有帖子的一對多關係。我正在實現的API將網站列表作爲JSON對象返回,並且每個網站都有一個嵌套的posts列表。該結構看起來有點像這個優化SQL中的數據訪問

 
{ 
    "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格姆正在運行來實現這一點,我意識到,這是做一個選擇的職位在每個站點名單。所以我試圖像這樣使用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 

編輯:看來,如果我做了確切的代碼我提出的這個問題,GORM實際上並沒有做N + 1個選擇,它運行兩個查詢,一個簡單的選擇網站和一個SELECT ... WHERE ... IN ...發帖,然後整理兩個結果集。我仍然想知道如何在SQLx中做到這一點。

+0

有沒有神奇。只需要首先請求mysql的站點,然後使用簡單的循環提取ID。然後用WHERE ID IN()做第二次請求。最後,使用兩個使用簡單循環的數據集構建新的數據結構。只需使用普通的SQL和SQLx API就可以很好地記錄。 –

+0

我並不期待魔術。我可以編寫一個函數來使用我的單個SQL語句,並創建並填寫Site結構和Post結構。我想我必須寫一個。但我想將其隱藏在行掃描過程中,所以表面上我可以使用本機SQLx API。 –

回答

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)