From c8c60f4ee409d5a9411cfb3dbdae3ee050d00165 Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Wed, 29 Jul 2020 20:10:55 +0200 Subject: [PATCH 1/2] services/horizon/db2/history: Improve /trades DB queries performance --- services/horizon/internal/db2/history/main.go | 16 ++- .../horizon/internal/db2/history/trade.go | 98 +++++++++++++++---- .../internal/db2/history/trade_test.go | 97 +++++++++++++++++- .../horizon/internal/db2/schema/bindata.go | 23 +++++ .../migrations/39_history_trades_indices.sql | 7 ++ 5 files changed, 215 insertions(+), 26 deletions(-) create mode 100644 services/horizon/internal/db2/schema/migrations/39_history_trades_indices.sql diff --git a/services/horizon/internal/db2/history/main.go b/services/horizon/internal/db2/history/main.go index 725b61810a..6cf1480663 100644 --- a/services/horizon/internal/db2/history/main.go +++ b/services/horizon/internal/db2/history/main.go @@ -547,9 +547,19 @@ type Trade struct { // TradesQ is a helper struct to aid in configuring queries that loads // slices of trade structs. type TradesQ struct { - Err error - parent *Q - sql sq.SelectBuilder + Err error + parent *Q + sql sq.SelectBuilder + pageCalled bool + + // For queries for account and offer we construct UNION query. The alternative + // is to use (base = X OR counter = X) query but it's costly. + forAccountID int64 + forOfferID int64 + + // rawSQL will be executed if present (instead of sql - sq.SelectBuilder). + rawSQL string + rawArgs []interface{} } // Transaction is a row of data from the `history_transactions` table diff --git a/services/horizon/internal/db2/history/trade.go b/services/horizon/internal/db2/history/trade.go index 6b46a88b89..00fa50c6db 100644 --- a/services/horizon/internal/db2/history/trade.go +++ b/services/horizon/internal/db2/history/trade.go @@ -7,6 +7,7 @@ import ( sq "github.com/Masterminds/squirrel" "github.com/stellar/go/services/horizon/internal/db2" "github.com/stellar/go/services/horizon/internal/toid" + "github.com/stellar/go/support/errors" "github.com/stellar/go/xdr" ) @@ -65,7 +66,7 @@ func (q *Q) TradesForAssetPair(baseAssetId int64, counterAssetId int64) *TradesQ // ForOffer filters the query results by the offer id. func (q *TradesQ) ForOffer(id int64) *TradesQ { - q.sql = q.sql.Where("(htrd.base_offer_id = ? OR htrd.counter_offer_id = ?)", id, id) + q.forOfferID = id return q } @@ -99,7 +100,7 @@ func (q *TradesQ) ForAccount(aid string) *TradesQ { return q } - q.sql = q.sql.Where("(htrd.base_account_id = ? OR htrd.counter_account_id = ?)", account.ID, account.ID) + q.forAccountID = account.ID return q } @@ -120,42 +121,101 @@ func (q *TradesQ) Page(page db2.PageQuery) *TradesQ { idx = math.MaxInt32 } + q.pageCalled = true + + if q.forAccountID != 0 || q.forOfferID != 0 { + // Construct UNION query + var firstSelect, secondSelect sq.SelectBuilder + switch { + case q.forAccountID != 0: + firstSelect = q.sql.Where("htrd.base_account_id = ?", q.forAccountID) + secondSelect = q.sql.Where("htrd.counter_account_id = ?", q.forAccountID) + case q.forOfferID != 0: + firstSelect = q.sql.Where("htrd.base_offer_id = ?", q.forOfferID) + secondSelect = q.sql.Where("htrd.counter_offer_id = ?", q.forOfferID) + } + + firstSelect = q.appendOrdering(firstSelect, op, idx, page.Order) + secondSelect = q.appendOrdering(secondSelect, op, idx, page.Order) + + firstSQL, firstArgs, err := firstSelect.ToSql() + if err != nil { + q.Err = errors.New("error building a firstSelect query") + return q + } + secondSQL, secondArgs, err := secondSelect.ToSql() + if err != nil { + q.Err = errors.New("error building a secondSelect query") + return q + } + + q.rawSQL = fmt.Sprintf("(%s) UNION (%s) ", firstSQL, secondSQL) + q.rawArgs = append(q.rawArgs, firstArgs...) + q.rawArgs = append(q.rawArgs, secondArgs...) + // Order the final UNION: + switch page.Order { + case "asc": + q.rawSQL = q.rawSQL + `ORDER BY history_operation_id asc, "order" asc ` + case "desc": + q.rawSQL = q.rawSQL + `ORDER BY history_operation_id desc, "order" desc ` + default: + panic("Invalid order") + } + q.rawSQL = q.rawSQL + fmt.Sprintf("LIMIT %d", page.Limit) + // Reset sql so it's not used accidentally + q.sql = sq.SelectBuilder{} + } else { + q.sql = q.appendOrdering(q.sql, op, idx, page.Order) + } + + q.sql = q.sql.Limit(page.Limit) + return q +} + +func (q *TradesQ) appendOrdering(sel sq.SelectBuilder, op, idx int64, order string) sq.SelectBuilder { // NOTE: Remember to test the queries below with EXPLAIN / EXPLAIN ANALYZE // before changing them. // This condition is using multicolumn index and it's easy to write it in a way that // DB will perform a full table scan. - switch page.Order { + switch order { case "asc": - q.sql = q.sql. + return sel. Where(`( - htrd.history_operation_id >= ? - AND ( - htrd.history_operation_id > ? OR - (htrd.history_operation_id = ? AND htrd.order > ?) - ))`, op, op, op, idx). + htrd.history_operation_id >= ? + AND ( + htrd.history_operation_id > ? OR + (htrd.history_operation_id = ? AND htrd.order > ?) + ))`, op, op, op, idx). OrderBy("htrd.history_operation_id asc, htrd.order asc") case "desc": - q.sql = q.sql. + return sel. Where(`( - htrd.history_operation_id <= ? - AND ( - htrd.history_operation_id < ? OR - (htrd.history_operation_id = ? AND htrd.order < ?) - ))`, op, op, op, idx). + htrd.history_operation_id <= ? + AND ( + htrd.history_operation_id < ? OR + (htrd.history_operation_id = ? AND htrd.order < ?) + ))`, op, op, op, idx). OrderBy("htrd.history_operation_id desc, htrd.order desc") + default: + panic("Invalid order") } - - q.sql = q.sql.Limit(page.Limit) - return q } // Select loads the results of the query specified by `q` into `dest`. func (q *TradesQ) Select(dest interface{}) error { + if !q.pageCalled { + return errors.New("TradesQ.Page call is required before calling Select") + } + if q.Err != nil { return q.Err } - q.Err = q.parent.Select(dest, q.sql) + if q.rawSQL != "" { + q.Err = q.parent.SelectRaw(dest, q.rawSQL, q.rawArgs...) + } else { + q.Err = q.parent.Select(dest, q.sql) + } return q.Err } diff --git a/services/horizon/internal/db2/history/trade_test.go b/services/horizon/internal/db2/history/trade_test.go index 16784e0569..b96ea1cf29 100644 --- a/services/horizon/internal/db2/history/trade_test.go +++ b/services/horizon/internal/db2/history/trade_test.go @@ -48,14 +48,14 @@ func TestTradeQueries(t *testing.T) { assetEUR, err := q.GetAssetID(xdr.MustNewCreditAsset("EUR", "GAXMF43TGZHW3QN3REOUA2U5PW5BTARXGGYJ3JIFHW3YT6QRKRL3CPPU")) tt.Require.NoError(err) - err = q.TradesForAssetPair(assetUSD, assetEUR).Select(&trades) + err = q.TradesForAssetPair(assetUSD, assetEUR).Page(db2.MustPageQuery("", false, "asc", 100)).Select(&trades) tt.Require.NoError(err) tt.Assert.Len(trades, 0) assetUSD, err = q.GetAssetID(xdr.MustNewCreditAsset("USD", "GAXMF43TGZHW3QN3REOUA2U5PW5BTARXGGYJ3JIFHW3YT6QRKRL3CPPU")) tt.Require.NoError(err) - err = q.TradesForAssetPair(lumen, assetUSD).Select(&trades) + err = q.TradesForAssetPair(lumen, assetUSD).Page(db2.MustPageQuery("", false, "asc", 100)).Select(&trades) tt.Require.NoError(err) tt.Assert.Len(trades, 1) @@ -64,7 +64,7 @@ func TestTradeQueries(t *testing.T) { tt.Assert.Equal(true, trades[0].BaseIsSeller) // reverse assets - err = q.TradesForAssetPair(assetUSD, lumen).Select(&trades) + err = q.TradesForAssetPair(assetUSD, lumen).Page(db2.MustPageQuery("", false, "asc", 100)).Select(&trades) tt.Require.NoError(err) tt.Assert.Len(trades, 1) @@ -199,7 +199,7 @@ func TestBatchInsertTrade(t *testing.T) { tt.Assert.NoError(builder.Exec()) var rows []Trade - tt.Assert.NoError(q.Trades().Select(&rows)) + tt.Assert.NoError(q.Trades().Page(db2.MustPageQuery("", false, "asc", 100)).Select(&rows)) idToAccount := buildIDtoAccountMapping(addresses, accountIDs) idToAsset := buildIDtoAssetMapping(assets, assetIDs) @@ -313,3 +313,92 @@ func TestBatchInsertTrade(t *testing.T) { ) } } + +func TestTradesQueryForAccount(t *testing.T) { + tt := test.Start(t).Scenario("kahuna") + defer tt.Finish() + q := &Q{tt.HorizonSession()} + tradesQ := q.Trades() + var trades []Trade + + account := "GAXMF43TGZHW3QN3REOUA2U5PW5BTARXGGYJ3JIFHW3YT6QRKRL3CPPU" + tradesQ.ForAccount(account) + tt.Assert.Equal(int64(15), tradesQ.forAccountID) + tt.Assert.Equal(int64(0), tradesQ.forOfferID) + + tradesQ.Page(db2.MustPageQuery("", false, "desc", 100)) + _, _, err := tradesQ.sql.ToSql() + // q.sql was reset in Page so should return error + tt.Assert.EqualError(err, "select statements must have at least one result column") + + expectedRawSQL := `(SELECT history_operation_id, htrd."order", htrd.ledger_closed_at, htrd.offer_id, htrd.base_offer_id, base_accounts.address as base_account, base_assets.asset_type as base_asset_type, base_assets.asset_code as base_asset_code, base_assets.asset_issuer as base_asset_issuer, htrd.base_amount, htrd.counter_offer_id, counter_accounts.address as counter_account, counter_assets.asset_type as counter_asset_type, counter_assets.asset_code as counter_asset_code, counter_assets.asset_issuer as counter_asset_issuer, htrd.counter_amount, htrd.base_is_seller, htrd.price_n, htrd.price_d FROM history_trades htrd JOIN history_accounts base_accounts ON base_account_id = base_accounts.id JOIN history_accounts counter_accounts ON counter_account_id = counter_accounts.id JOIN history_assets base_assets ON base_asset_id = base_assets.id JOIN history_assets counter_assets ON counter_asset_id = counter_assets.id WHERE htrd.base_account_id = ? AND ( + htrd.history_operation_id <= ? + AND ( + htrd.history_operation_id < ? OR + (htrd.history_operation_id = ? AND htrd.order < ?) + )) ORDER BY htrd.history_operation_id desc, htrd.order desc) UNION (SELECT history_operation_id, htrd."order", htrd.ledger_closed_at, htrd.offer_id, htrd.base_offer_id, base_accounts.address as base_account, base_assets.asset_type as base_asset_type, base_assets.asset_code as base_asset_code, base_assets.asset_issuer as base_asset_issuer, htrd.base_amount, htrd.counter_offer_id, counter_accounts.address as counter_account, counter_assets.asset_type as counter_asset_type, counter_assets.asset_code as counter_asset_code, counter_assets.asset_issuer as counter_asset_issuer, htrd.counter_amount, htrd.base_is_seller, htrd.price_n, htrd.price_d FROM history_trades htrd JOIN history_accounts base_accounts ON base_account_id = base_accounts.id JOIN history_accounts counter_accounts ON counter_account_id = counter_accounts.id JOIN history_assets base_assets ON base_asset_id = base_assets.id JOIN history_assets counter_assets ON counter_asset_id = counter_assets.id WHERE htrd.counter_account_id = ? AND ( + htrd.history_operation_id <= ? + AND ( + htrd.history_operation_id < ? OR + (htrd.history_operation_id = ? AND htrd.order < ?) + )) ORDER BY htrd.history_operation_id desc, htrd.order desc) ORDER BY history_operation_id desc, "order" desc LIMIT 100` + tt.Assert.Equal(expectedRawSQL, tradesQ.rawSQL) + + err = tradesQ.Select(&trades) + tt.Assert.NoError(err) + tt.Assert.Len(trades, 3) + + // Ensure "desc" order and account present + tt.Assert.Equal(int64(85899350017), trades[0].HistoryOperationID) + tt.Assert.Equal(account, trades[0].BaseAccount) + + tt.Assert.Equal(int64(81604382721), trades[1].HistoryOperationID) + tt.Assert.Equal(int32(1), trades[1].Order) + tt.Assert.Equal(account, trades[1].BaseAccount) + + tt.Assert.Equal(int64(81604382721), trades[2].HistoryOperationID) + tt.Assert.Equal(int32(0), trades[2].Order) + tt.Assert.Equal(account, trades[2].CounterAccount) +} + +func TestTradesQueryForOffer(t *testing.T) { + tt := test.Start(t).Scenario("kahuna") + defer tt.Finish() + q := &Q{tt.HorizonSession()} + tradesQ := q.Trades() + var trades []Trade + + offerID := int64(2) + tradesQ.ForOffer(offerID) + tt.Assert.Equal(int64(0), tradesQ.forAccountID) + tt.Assert.Equal(int64(2), tradesQ.forOfferID) + + tradesQ.Page(db2.MustPageQuery("", false, "asc", 100)) + _, _, err := tradesQ.sql.ToSql() + // q.sql was reset in Page so should return error + tt.Assert.EqualError(err, "select statements must have at least one result column") + + expectedRawSQL := `(SELECT history_operation_id, htrd."order", htrd.ledger_closed_at, htrd.offer_id, htrd.base_offer_id, base_accounts.address as base_account, base_assets.asset_type as base_asset_type, base_assets.asset_code as base_asset_code, base_assets.asset_issuer as base_asset_issuer, htrd.base_amount, htrd.counter_offer_id, counter_accounts.address as counter_account, counter_assets.asset_type as counter_asset_type, counter_assets.asset_code as counter_asset_code, counter_assets.asset_issuer as counter_asset_issuer, htrd.counter_amount, htrd.base_is_seller, htrd.price_n, htrd.price_d FROM history_trades htrd JOIN history_accounts base_accounts ON base_account_id = base_accounts.id JOIN history_accounts counter_accounts ON counter_account_id = counter_accounts.id JOIN history_assets base_assets ON base_asset_id = base_assets.id JOIN history_assets counter_assets ON counter_asset_id = counter_assets.id WHERE htrd.base_offer_id = ? AND ( + htrd.history_operation_id >= ? + AND ( + htrd.history_operation_id > ? OR + (htrd.history_operation_id = ? AND htrd.order > ?) + )) ORDER BY htrd.history_operation_id asc, htrd.order asc) UNION (SELECT history_operation_id, htrd."order", htrd.ledger_closed_at, htrd.offer_id, htrd.base_offer_id, base_accounts.address as base_account, base_assets.asset_type as base_asset_type, base_assets.asset_code as base_asset_code, base_assets.asset_issuer as base_asset_issuer, htrd.base_amount, htrd.counter_offer_id, counter_accounts.address as counter_account, counter_assets.asset_type as counter_asset_type, counter_assets.asset_code as counter_asset_code, counter_assets.asset_issuer as counter_asset_issuer, htrd.counter_amount, htrd.base_is_seller, htrd.price_n, htrd.price_d FROM history_trades htrd JOIN history_accounts base_accounts ON base_account_id = base_accounts.id JOIN history_accounts counter_accounts ON counter_account_id = counter_accounts.id JOIN history_assets base_assets ON base_asset_id = base_assets.id JOIN history_assets counter_assets ON counter_asset_id = counter_assets.id WHERE htrd.counter_offer_id = ? AND ( + htrd.history_operation_id >= ? + AND ( + htrd.history_operation_id > ? OR + (htrd.history_operation_id = ? AND htrd.order > ?) + )) ORDER BY htrd.history_operation_id asc, htrd.order asc) ORDER BY history_operation_id asc, "order" asc LIMIT 100` + tt.Assert.Equal(expectedRawSQL, tradesQ.rawSQL) + + err = tradesQ.Select(&trades) + tt.Assert.NoError(err) + tt.Assert.Len(trades, 2) + + // Ensure "asc" order and offer present + tt.Assert.Equal(int64(81604382721), trades[0].HistoryOperationID) + tt.Assert.Equal(offerID, trades[0].OfferID) + + tt.Assert.Equal(int64(85899350017), trades[1].HistoryOperationID) + tt.Assert.Equal(offerID, trades[1].OfferID) +} diff --git a/services/horizon/internal/db2/schema/bindata.go b/services/horizon/internal/db2/schema/bindata.go index b759237372..e6480a8f16 100644 --- a/services/horizon/internal/db2/schema/bindata.go +++ b/services/horizon/internal/db2/schema/bindata.go @@ -31,6 +31,7 @@ // migrations/36_deleted_offers.sql (956B) // migrations/37_add_tx_set_operation_count_to_ledgers.sql (176B) // migrations/38_add_constraints.sql (7.33kB) +// migrations/39_history_trades_indices.sql (183B) // migrations/3_use_sequence_in_history_accounts.sql (447B) // migrations/4_add_protocol_version.sql (188B) // migrations/5_create_trades_table.sql (1.1kB) @@ -727,6 +728,26 @@ func migrations38_add_constraintsSql() (*asset, error) { return a, nil } +var _migrations39_history_trades_indicesSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\xce\xb1\x0a\xc2\x40\x0c\x80\xe1\x3d\x4f\x11\x3a\x29\xda\x27\xe8\xa4\xf6\x90\x2e\xad\xd4\x16\xdc\x8e\xd3\x0b\x36\x83\xcd\x91\x8b\x88\x6f\x2f\x08\x42\x07\xd7\x1f\x7e\xf8\xca\x12\x37\x0f\xbe\x6b\x30\xc2\x31\x01\x1c\x7a\xb7\x1b\x1c\x36\x6d\xed\x2e\x38\x99\x46\x9f\x02\xab\x4f\x1c\xb1\x6b\x71\xe2\x6c\xa2\x6f\x6f\x1a\x22\x65\x1c\xcf\x4d\x7b\xc4\xfd\xd0\x3b\xb7\xba\x86\x4c\x3e\xe4\x4c\xe6\x39\x6e\xf1\x26\xcf\xd9\x48\x17\xe5\xf7\x4a\x22\x0d\xc6\x32\x7f\x6b\x21\x1a\x49\x8b\x75\x05\xb0\xa4\xd4\xf2\x9a\x01\xea\xbe\x3b\xfd\xa3\x54\xf0\x09\x00\x00\xff\xff\xb2\xf0\x3e\xfe\xb7\x00\x00\x00") + +func migrations39_history_trades_indicesSqlBytes() ([]byte, error) { + return bindataRead( + _migrations39_history_trades_indicesSql, + "migrations/39_history_trades_indices.sql", + ) +} + +func migrations39_history_trades_indicesSql() (*asset, error) { + bytes, err := migrations39_history_trades_indicesSqlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "migrations/39_history_trades_indices.sql", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x50, 0x44, 0xfd, 0xa3, 0xc4, 0xc9, 0x68, 0x24, 0xb5, 0xf7, 0xea, 0xf3, 0x46, 0xb9, 0x2, 0xc1, 0x2d, 0xe7, 0xce, 0xd3, 0x42, 0x93, 0x2e, 0x87, 0x22, 0xca, 0xad, 0x97, 0xa9, 0xa, 0x6a, 0xe3}} + return a, nil +} + var _migrations3_use_sequence_in_history_accountsSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x91\x4d\x6b\xb3\x40\x14\x85\xf7\xf3\x2b\xce\x2e\xca\xfb\x66\x91\x6d\x5c\x4d\xc6\x1b\x22\x8c\x63\x3b\x5e\xdb\x64\x25\xa2\x43\x3a\x90\x6a\xeb\xd8\xaf\x7f\x5f\x48\xd3\x0f\x08\x6d\xa1\xcb\x73\x78\xe0\x39\xdc\x3b\x9f\xe3\xdf\xad\xdf\x8f\xcd\xe4\x50\xdd\x09\x65\x49\x32\xa1\xa4\xcb\x8a\x8c\x22\xdc\xf8\x30\x0d\xe3\x4b\xdd\xb4\xed\xf0\xd0\x4f\xa1\xf6\x5d\x1d\xdc\xbd\x00\x80\x92\xa5\x65\x5c\x67\xbc\xc1\xe2\x58\x64\x46\x59\xca\xc9\x30\x56\xbb\x53\x65\x0a\xe4\x99\xb9\x92\xba\xa2\x8f\x2c\xb7\x9f\x59\x49\xb5\x21\x2c\x12\x51\x92\x26\xc5\x08\x6e\x7a\x6c\x0e\xd1\xec\x1b\xef\xec\x3f\xa2\x13\x99\xcb\x6d\xe4\xbb\x18\x6b\x5b\xe4\x67\x33\xe3\x38\x11\x52\x33\x59\xb0\x5c\x69\x42\x61\xf4\xee\x0c\xc2\x1b\xa1\x0a\x5d\xe5\x06\xbe\x43\x49\x8c\x94\xd6\xb2\xd2\x8c\xde\x3d\xff\xbc\x64\xb9\x1c\xdd\xbe\x3d\x34\x21\xc4\x89\x10\x5f\xcf\x98\x0e\x4f\xfd\x1f\xec\xa9\x2d\x2e\xde\xf5\x89\x38\xa6\xdf\xde\x90\x88\xd7\x00\x00\x00\xff\xff\x55\xe2\xdd\x2c\xbf\x01\x00\x00") func migrations3_use_sequence_in_history_accountsSqlBytes() ([]byte, error) { @@ -1009,6 +1030,7 @@ var _bindata = map[string]func() (*asset, error){ "migrations/36_deleted_offers.sql": migrations36_deleted_offersSql, "migrations/37_add_tx_set_operation_count_to_ledgers.sql": migrations37_add_tx_set_operation_count_to_ledgersSql, "migrations/38_add_constraints.sql": migrations38_add_constraintsSql, + "migrations/39_history_trades_indices.sql": migrations39_history_trades_indicesSql, "migrations/3_use_sequence_in_history_accounts.sql": migrations3_use_sequence_in_history_accountsSql, "migrations/4_add_protocol_version.sql": migrations4_add_protocol_versionSql, "migrations/5_create_trades_table.sql": migrations5_create_trades_tableSql, @@ -1092,6 +1114,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "36_deleted_offers.sql": &bintree{migrations36_deleted_offersSql, map[string]*bintree{}}, "37_add_tx_set_operation_count_to_ledgers.sql": &bintree{migrations37_add_tx_set_operation_count_to_ledgersSql, map[string]*bintree{}}, "38_add_constraints.sql": &bintree{migrations38_add_constraintsSql, map[string]*bintree{}}, + "39_history_trades_indices.sql": &bintree{migrations39_history_trades_indicesSql, map[string]*bintree{}}, "3_use_sequence_in_history_accounts.sql": &bintree{migrations3_use_sequence_in_history_accountsSql, map[string]*bintree{}}, "4_add_protocol_version.sql": &bintree{migrations4_add_protocol_versionSql, map[string]*bintree{}}, "5_create_trades_table.sql": &bintree{migrations5_create_trades_tableSql, map[string]*bintree{}}, diff --git a/services/horizon/internal/db2/schema/migrations/39_history_trades_indices.sql b/services/horizon/internal/db2/schema/migrations/39_history_trades_indices.sql new file mode 100644 index 0000000000..93ed26f601 --- /dev/null +++ b/services/horizon/internal/db2/schema/migrations/39_history_trades_indices.sql @@ -0,0 +1,7 @@ +-- +migrate Up + +CREATE INDEX htrd_pair_pid ON history_trades USING BTREE(base_asset_id, counter_asset_id, history_operation_id, "order"); + +-- +migrate Down + +DROP INDEX htrd_pair_pid; From 013fdcbf62d3e64c0ebcda6e2dab39ba1697bdbb Mon Sep 17 00:00:00 2001 From: Bartek Nowotarski Date: Wed, 29 Jul 2020 20:55:25 +0200 Subject: [PATCH 2/2] Review fixes --- services/horizon/internal/db2/history/trade.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/horizon/internal/db2/history/trade.go b/services/horizon/internal/db2/history/trade.go index 00fa50c6db..d7b7735c04 100644 --- a/services/horizon/internal/db2/history/trade.go +++ b/services/horizon/internal/db2/history/trade.go @@ -166,9 +166,8 @@ func (q *TradesQ) Page(page db2.PageQuery) *TradesQ { q.sql = sq.SelectBuilder{} } else { q.sql = q.appendOrdering(q.sql, op, idx, page.Order) + q.sql = q.sql.Limit(page.Limit) } - - q.sql = q.sql.Limit(page.Limit) return q }