From 7e884fd04f0d6eb03cc1d1c667573aa1d96daa0d Mon Sep 17 00:00:00 2001 From: Eliot Whalan Date: Mon, 8 May 2017 23:50:18 +1000 Subject: [PATCH] Optimize sql queries --- main.go | 2 -- service/torrent/torrent.go | 16 +++++++++++----- util/search/search.go | 30 +++++++++++++++--------------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/main.go b/main.go index 2784a9c5..f697cc9d 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,6 @@ import ( "github.com/ewhal/nyaa/network" "github.com/ewhal/nyaa/router" "github.com/ewhal/nyaa/util/log" - "github.com/ewhal/nyaa/util/search" // super hacky fix "github.com/ewhal/nyaa/util/signals" "net/http" @@ -61,7 +60,6 @@ func main() { if len(config.TorrentFileStorage) > 0 { os.MkdirAll(config.TorrentFileStorage, 0755) } - search.Init(conf.DBType) // super hacky fix RunServer(conf) } } diff --git a/service/torrent/torrent.go b/service/torrent/torrent.go index 1e5260e7..40191c17 100644 --- a/service/torrent/torrent.go +++ b/service/torrent/torrent.go @@ -6,8 +6,8 @@ import ( "github.com/ewhal/nyaa/db" "github.com/ewhal/nyaa/model" "github.com/ewhal/nyaa/util" - "github.com/jinzhu/gorm" "strings" + "strconv" ) type WhereParams struct { @@ -54,7 +54,6 @@ func GetTorrentById(id string) (model.Torrents, error) { func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offset int) ([]model.Torrents, int) { var torrents []model.Torrents - var dbQuery *gorm.DB var count int conditions := "torrent_hash IS NOT NULL" // filter out broken entries if strings.HasPrefix(orderBy, "filesize") { @@ -69,15 +68,22 @@ func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offs params = parameters.Params } db.ORM.Model(&torrents).Where(conditions, params...).Count(&count) - dbQuery = db.ORM.Model(&torrents).Where(conditions, params...) + dbQuery := "SELECT * FROM torrents" + if conditions != "" { + dbQuery = dbQuery + " WHERE " + conditions + } + if strings.Contains(conditions, "torrent_name") { + dbQuery = "WITH t AS (SELECT * FROM torrents WHERE " + conditions + ") SELECT * FROM t" + } if orderBy == "" { // default OrderBy orderBy = "torrent_id DESC" } + dbQuery = dbQuery + " ORDER BY " + orderBy if limit != 0 || offset != 0 { // if limits provided - dbQuery = dbQuery.Limit(limit).Offset(offset) + dbQuery = dbQuery + " LIMIT " + strconv.Itoa(limit) + " OFFSET " + strconv.Itoa(offset) } - dbQuery.Order(orderBy).Find(&torrents) + db.ORM.Raw(dbQuery, params...).Find(&torrents) return torrents, count } diff --git a/util/search/search.go b/util/search/search.go index 3872adff..12caa2ec 100644 --- a/util/search/search.go +++ b/util/search/search.go @@ -8,6 +8,8 @@ import ( "net/http" "strconv" "strings" + "unicode" + "unicode/utf8" ) type SearchParam struct { @@ -19,17 +21,6 @@ type SearchParam struct { Sort string } - -// super hacky fix: -var search_op string -func Init(backend string) { - if backend == "postgres" { - search_op = "ILIKE" - } else { - search_op = "LIKE" - } -} - func SearchByQuery(r *http.Request, pagenum int) (SearchParam, []model.Torrents, int) { maxPerPage, errConv := strconv.Atoi(r.URL.Query().Get("max")) if errConv != nil { @@ -81,10 +72,19 @@ func SearchByQuery(r *http.Request, pagenum int) (SearchParam, []model.Torrents, } parameters.Params = append(parameters.Params, search_param.Status) } - searchQuerySplit := strings.Split(search_param.Query, " ") - for i, _ := range searchQuerySplit { - conditions = append(conditions, "torrent_name " + search_op + " ?") - parameters.Params = append(parameters.Params, "%"+searchQuerySplit[i]+"%") + searchQuerySplit := strings.Fields(search_param.Query) + for i, word := range searchQuerySplit { + firstRune, _ := utf8.DecodeRuneInString(word) + if len(word) == 1 && unicode.IsPunct(firstRune) { + // some queries have a single punctuation character + // which causes a full scan instead of using the index + // and yields no meaningful results. + // due to len() == 1 we're just looking at 1-byte/ascii + // punctuation characters. + continue + } + conditions = append(conditions, "torrent_name %> ?") + parameters.Params = append(parameters.Params, searchQuerySplit[i]) } parameters.Conditions = strings.Join(conditions[:], " AND ")