فهرست منبع

performance improvement via string builder

xormplus 7 سال پیش
والد
کامیت
a2417f1c7a
3فایلهای تغییر یافته به همراه35 افزوده شده و 40 حذف شده
  1. 1 1
      engine.go
  2. 4 6
      session_insert.go
  3. 30 33
      statement.go

+ 1 - 1
engine.go

@@ -197,7 +197,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
 	}
 	}

+ 4 - 6
session_insert.go

@@ -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 statement string
+	var sql 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
 	}
 	}

+ 30 - 33
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
-	fmt.Fprintf(&buf, statement.OrderStr)
+	var buf builder.StringBuilder
 	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
-	fmt.Fprintf(&buf, statement.OrderStr)
+	var buf builder.StringBuilder
 	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 {
@@ -1029,23 +1026,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) {
-	var distinct string
+func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, needOrderBy bool) (string, error) {
+	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()
@@ -1105,43 +1099,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
-	a = fmt.Sprintf("SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr)
+	var buf builder.StringBuilder
+	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 {