performance improvement via string builder (#1036)
This commit is contained in:
parent
f16ce722ec
commit
ad69f7d8f0
|
@ -194,7 +194,7 @@ func (engine *Engine) Quote(value string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuoteTo quotes string and writes into the buffer
|
// QuoteTo quotes string and writes into the buffer
|
||||||
func (engine *Engine) QuoteTo(buf *bytes.Buffer, value string) {
|
func (engine *Engine) QuoteTo(buf *builder.StringBuilder, value string) {
|
||||||
if buf == nil {
|
if buf == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,30 +204,28 @@ func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error
|
||||||
}
|
}
|
||||||
cleanupProcessorsClosures(&session.beforeClosures)
|
cleanupProcessorsClosures(&session.beforeClosures)
|
||||||
|
|
||||||
var sql = "INSERT INTO %s (%v%v%v) VALUES (%v)"
|
var sql string
|
||||||
var statement string
|
|
||||||
if session.engine.dialect.DBType() == core.ORACLE {
|
if session.engine.dialect.DBType() == core.ORACLE {
|
||||||
sql = "INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL"
|
|
||||||
temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
|
temp := fmt.Sprintf(") INTO %s (%v%v%v) VALUES (",
|
||||||
session.engine.Quote(tableName),
|
session.engine.Quote(tableName),
|
||||||
session.engine.QuoteStr(),
|
session.engine.QuoteStr(),
|
||||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
||||||
session.engine.QuoteStr())
|
session.engine.QuoteStr())
|
||||||
statement = fmt.Sprintf(sql,
|
sql = fmt.Sprintf("INSERT ALL INTO %s (%v%v%v) VALUES (%v) SELECT 1 FROM DUAL",
|
||||||
session.engine.Quote(tableName),
|
session.engine.Quote(tableName),
|
||||||
session.engine.QuoteStr(),
|
session.engine.QuoteStr(),
|
||||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
||||||
session.engine.QuoteStr(),
|
session.engine.QuoteStr(),
|
||||||
strings.Join(colMultiPlaces, temp))
|
strings.Join(colMultiPlaces, temp))
|
||||||
} else {
|
} else {
|
||||||
statement = fmt.Sprintf(sql,
|
sql = fmt.Sprintf("INSERT INTO %s (%v%v%v) VALUES (%v)",
|
||||||
session.engine.Quote(tableName),
|
session.engine.Quote(tableName),
|
||||||
session.engine.QuoteStr(),
|
session.engine.QuoteStr(),
|
||||||
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
strings.Join(colNames, session.engine.QuoteStr()+", "+session.engine.QuoteStr()),
|
||||||
session.engine.QuoteStr(),
|
session.engine.QuoteStr(),
|
||||||
strings.Join(colMultiPlaces, "),("))
|
strings.Join(colMultiPlaces, "),("))
|
||||||
}
|
}
|
||||||
res, err := session.exec(statement, args...)
|
res, err := session.exec(sql, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
63
statement.go
63
statement.go
|
@ -5,7 +5,6 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -706,10 +705,9 @@ func (statement *Statement) OrderBy(order string) *Statement {
|
||||||
|
|
||||||
// Desc generate `ORDER BY xx DESC`
|
// Desc generate `ORDER BY xx DESC`
|
||||||
func (statement *Statement) Desc(colNames ...string) *Statement {
|
func (statement *Statement) Desc(colNames ...string) *Statement {
|
||||||
var buf bytes.Buffer
|
var buf builder.StringBuilder
|
||||||
fmt.Fprintf(&buf, statement.OrderStr)
|
|
||||||
if len(statement.OrderStr) > 0 {
|
if len(statement.OrderStr) > 0 {
|
||||||
fmt.Fprint(&buf, ", ")
|
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
||||||
}
|
}
|
||||||
newColNames := statement.col2NewColsWithQuote(colNames...)
|
newColNames := statement.col2NewColsWithQuote(colNames...)
|
||||||
fmt.Fprintf(&buf, "%v DESC", strings.Join(newColNames, " DESC, "))
|
fmt.Fprintf(&buf, "%v DESC", strings.Join(newColNames, " DESC, "))
|
||||||
|
@ -719,10 +717,9 @@ func (statement *Statement) Desc(colNames ...string) *Statement {
|
||||||
|
|
||||||
// Asc provide asc order by query condition, the input parameters are columns.
|
// Asc provide asc order by query condition, the input parameters are columns.
|
||||||
func (statement *Statement) Asc(colNames ...string) *Statement {
|
func (statement *Statement) Asc(colNames ...string) *Statement {
|
||||||
var buf bytes.Buffer
|
var buf builder.StringBuilder
|
||||||
fmt.Fprintf(&buf, statement.OrderStr)
|
|
||||||
if len(statement.OrderStr) > 0 {
|
if len(statement.OrderStr) > 0 {
|
||||||
fmt.Fprint(&buf, ", ")
|
fmt.Fprint(&buf, statement.OrderStr, ", ")
|
||||||
}
|
}
|
||||||
newColNames := statement.col2NewColsWithQuote(colNames...)
|
newColNames := statement.col2NewColsWithQuote(colNames...)
|
||||||
fmt.Fprintf(&buf, "%v ASC", strings.Join(newColNames, " ASC, "))
|
fmt.Fprintf(&buf, "%v ASC", strings.Join(newColNames, " ASC, "))
|
||||||
|
@ -749,7 +746,7 @@ func (statement *Statement) Table(tableNameOrBean interface{}) *Statement {
|
||||||
|
|
||||||
// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
|
// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
|
||||||
func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
|
func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
|
||||||
var buf bytes.Buffer
|
var buf builder.StringBuilder
|
||||||
if len(statement.JoinStr) > 0 {
|
if len(statement.JoinStr) > 0 {
|
||||||
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
|
fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
|
||||||
} else {
|
} else {
|
||||||
|
@ -783,11 +780,11 @@ func (statement *Statement) Unscoped() *Statement {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (statement *Statement) genColumnStr() string {
|
func (statement *Statement) genColumnStr() string {
|
||||||
var buf bytes.Buffer
|
|
||||||
if statement.RefTable == nil {
|
if statement.RefTable == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var buf builder.StringBuilder
|
||||||
columns := statement.RefTable.Columns()
|
columns := statement.RefTable.Columns()
|
||||||
|
|
||||||
for _, col := range columns {
|
for _, col := range columns {
|
||||||
|
@ -1031,23 +1028,20 @@ func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (stri
|
||||||
return sqlStr, append(statement.joinArgs, condArgs...), nil
|
return sqlStr, append(statement.joinArgs, condArgs...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, needOrderBy bool) (a string, err error) {
|
func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, needOrderBy bool) (string, error) {
|
||||||
var distinct string
|
var (
|
||||||
|
distinct string
|
||||||
|
dialect = statement.Engine.Dialect()
|
||||||
|
quote = statement.Engine.Quote
|
||||||
|
fromStr = " FROM "
|
||||||
|
top, mssqlCondi, whereStr string
|
||||||
|
)
|
||||||
if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
|
if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") {
|
||||||
distinct = "DISTINCT "
|
distinct = "DISTINCT "
|
||||||
}
|
}
|
||||||
|
|
||||||
var dialect = statement.Engine.Dialect()
|
|
||||||
var quote = statement.Engine.Quote
|
|
||||||
var top string
|
|
||||||
var mssqlCondi string
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if len(condSQL) > 0 {
|
if len(condSQL) > 0 {
|
||||||
fmt.Fprintf(&buf, " WHERE %v", condSQL)
|
whereStr = " WHERE " + condSQL
|
||||||
}
|
}
|
||||||
var whereStr = buf.String()
|
|
||||||
var fromStr = " FROM "
|
|
||||||
|
|
||||||
if dialect.DBType() == core.MSSQL && strings.Contains(statement.TableName(), "..") {
|
if dialect.DBType() == core.MSSQL && strings.Contains(statement.TableName(), "..") {
|
||||||
fromStr += statement.TableName()
|
fromStr += statement.TableName()
|
||||||
|
@ -1107,43 +1101,46 @@ func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// !nashtsai! REVIEW Sprintf is considered slowest mean of string concatnation, better to work with builder pattern
|
var buf builder.StringBuilder
|
||||||
a = fmt.Sprintf("SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
|
fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
|
||||||
if len(mssqlCondi) > 0 {
|
if len(mssqlCondi) > 0 {
|
||||||
if len(whereStr) > 0 {
|
if len(whereStr) > 0 {
|
||||||
a += " AND " + mssqlCondi
|
fmt.Fprint(&buf, " AND ", mssqlCondi)
|
||||||
} else {
|
} else {
|
||||||
a += " WHERE " + mssqlCondi
|
fmt.Fprint(&buf, " WHERE ", mssqlCondi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if statement.GroupByStr != "" {
|
if statement.GroupByStr != "" {
|
||||||
a = fmt.Sprintf("%v GROUP BY %v", a, statement.GroupByStr)
|
fmt.Fprint(&buf, " GROUP BY ", statement.GroupByStr)
|
||||||
}
|
}
|
||||||
if statement.HavingStr != "" {
|
if statement.HavingStr != "" {
|
||||||
a = fmt.Sprintf("%v %v", a, statement.HavingStr)
|
fmt.Fprint(&buf, " ", statement.HavingStr)
|
||||||
}
|
}
|
||||||
if needOrderBy && statement.OrderStr != "" {
|
if needOrderBy && statement.OrderStr != "" {
|
||||||
a = fmt.Sprintf("%v ORDER BY %v", a, statement.OrderStr)
|
fmt.Fprint(&buf, " ORDER BY ", statement.OrderStr)
|
||||||
}
|
}
|
||||||
if needLimit {
|
if needLimit {
|
||||||
if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE {
|
if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE {
|
||||||
if statement.Start > 0 {
|
if statement.Start > 0 {
|
||||||
a = fmt.Sprintf("%v LIMIT %v OFFSET %v", a, statement.LimitN, statement.Start)
|
fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", statement.LimitN, statement.Start)
|
||||||
} else if statement.LimitN > 0 {
|
} else if statement.LimitN > 0 {
|
||||||
a = fmt.Sprintf("%v LIMIT %v", a, statement.LimitN)
|
fmt.Fprint(&buf, " LIMIT ", statement.LimitN)
|
||||||
}
|
}
|
||||||
} else if dialect.DBType() == core.ORACLE {
|
} else if dialect.DBType() == core.ORACLE {
|
||||||
if statement.Start != 0 || statement.LimitN != 0 {
|
if statement.Start != 0 || statement.LimitN != 0 {
|
||||||
a = fmt.Sprintf("SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", columnStr, columnStr, a, statement.Start+statement.LimitN, statement.Start)
|
oldString := buf.String()
|
||||||
|
buf.Reset()
|
||||||
|
fmt.Fprintf(&buf, "SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d",
|
||||||
|
columnStr, columnStr, oldString, statement.Start+statement.LimitN, statement.Start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if statement.IsForUpdate {
|
if statement.IsForUpdate {
|
||||||
a = dialect.ForUpdateSql(a)
|
return dialect.ForUpdateSql(buf.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (statement *Statement) processIDParam() error {
|
func (statement *Statement) processIDParam() error {
|
||||||
|
|
Loading…
Reference in New Issue