github.com/yongjacky/phoenix-go-orm-builder@v0.3.5/builder_b_test.go (about) 1 // Copyright 2018 The Xorm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package builder 6 7 import ( 8 "fmt" 9 "math/rand" 10 "testing" 11 ) 12 13 type randGenConf struct { 14 allowCond bool 15 allowJoin bool 16 allowLimit bool 17 allowUnion bool 18 allowHaving bool 19 allowGroupBy bool 20 allowOrderBy bool 21 allowSubQuery bool 22 } 23 24 var expectedValues = []interface{}{ 25 "dangerous", "fun", "degree", "hospital", "horseshoe", "summit", "parallel", "height", "recommend", "invite", 26 0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 27 28 var queryFields = []string{"f1", "f2", "f2", "f4", "f5", "f6", "f7", "f8", "f9"} 29 30 func BenchmarkSelect_Simple(b *testing.B) { 31 rgc := randGenConf{allowCond: true} 32 b.ResetTimer() 33 for i := 0; i < b.N; i++ { 34 randQuery("", &rgc).ToSQL() 35 } 36 } 37 38 func BenchmarkSelect_SubQuery(b *testing.B) { 39 rgc := randGenConf{allowSubQuery: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true} 40 b.ResetTimer() 41 for i := 0; i < b.N; i++ { 42 randQuery("", &rgc).ToSQL() 43 } 44 } 45 46 func BenchmarkSelect_SelectConditional4Oracle(b *testing.B) { 47 rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true} 48 for i := 0; i < b.N; i++ { 49 randQuery(ORACLE, &rgc).ToSQL() 50 } 51 } 52 53 func BenchmarkSelect_SelectConditional4Mssql(b *testing.B) { 54 rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true} 55 b.ResetTimer() 56 for i := 0; i < b.N; i++ { 57 randQuery(MSSQL, &rgc).ToSQL() 58 } 59 } 60 61 func BenchmarkSelect_SelectConditional4MysqlLike(b *testing.B) { 62 rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true} 63 b.ResetTimer() 64 for i := 0; i < b.N; i++ { 65 randQuery(MYSQL, &rgc).ToSQL() 66 } 67 } 68 69 func BenchmarkSelect_SelectConditional4Mixed(b *testing.B) { 70 rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true} 71 b.ResetTimer() 72 for i := 0; i < b.N; i++ { 73 randQuery(randDialect(), &rgc).ToSQL() 74 } 75 } 76 77 func BenchmarkSelect_SelectComplex4Oracle(b *testing.B) { 78 rgc := randGenConf{ 79 allowLimit: true, allowCond: true, 80 allowGroupBy: true, allowHaving: true, 81 allowOrderBy: true, allowSubQuery: true, 82 } 83 for i := 0; i < b.N; i++ { 84 randQuery(ORACLE, &rgc).ToSQL() 85 } 86 } 87 88 func BenchmarkSelect_SelectComplex4Mssql(b *testing.B) { 89 rgc := randGenConf{ 90 allowLimit: true, allowCond: true, 91 allowGroupBy: true, allowHaving: true, 92 allowOrderBy: true, allowSubQuery: true, 93 } 94 b.ResetTimer() 95 for i := 0; i < b.N; i++ { 96 randQuery(MSSQL, &rgc).ToSQL() 97 } 98 } 99 100 func BenchmarkSelect_SelectComplex4MysqlLike(b *testing.B) { 101 rgc := randGenConf{ 102 allowLimit: true, allowCond: true, 103 allowGroupBy: true, allowHaving: true, 104 allowOrderBy: true, allowSubQuery: true, 105 } 106 b.ResetTimer() 107 for i := 0; i < b.N; i++ { 108 randQuery(MYSQL, &rgc).ToSQL() 109 } 110 } 111 112 func BenchmarkSelect_SelectComplex4MysqlMixed(b *testing.B) { 113 rgc := randGenConf{ 114 allowLimit: true, allowCond: true, 115 allowGroupBy: true, allowHaving: true, 116 allowOrderBy: true, allowSubQuery: true, 117 } 118 b.ResetTimer() 119 for i := 0; i < b.N; i++ { 120 randQuery(randDialect(), &rgc).ToSQL() 121 } 122 } 123 124 func BenchmarkInsert(b *testing.B) { 125 rgc := randGenConf{allowCond: true} 126 b.ResetTimer() 127 for i := 0; i < b.N; i++ { 128 randInsertByCondition(&rgc).ToSQL() 129 } 130 } 131 132 func BenchmarkUpdate(b *testing.B) { 133 rgc := randGenConf{allowCond: true} 134 b.ResetTimer() 135 for i := 0; i < b.N; i++ { 136 randUpdateByCondition(&rgc).ToSQL() 137 } 138 } 139 140 // randQuery Generate a basic query for benchmark test. But be careful it's not a executable SQL in real db. 141 func randQuery(dialect string, rgc *randGenConf) *Builder { 142 b := randSelectByCondition(dialect, rgc) 143 isUnionized := rgc.allowUnion && rand.Intn(1000) >= 500 144 if isUnionized { 145 r := rand.Intn(3) + 1 146 for i := r; i < r; i++ { 147 b = b.Union("all", randSelectByCondition(dialect, rgc)) 148 } 149 } 150 151 if isUnionized && rgc.allowLimit && rand.Intn(1000) >= 500 { 152 b = randLimit(Dialect(dialect).Select().From(b, "t")) 153 } 154 155 return b 156 } 157 158 func randInsertByCondition(rgc *randGenConf) *Builder { 159 fields := randSelects() 160 161 times := rand.Intn(10) + 1 162 163 eqs := Eq{} 164 for i := 0; i < times; i++ { 165 eqs[fields[rand.Intn(len(fields))]] = "expected" 166 } 167 168 b := Insert(eqs).From("table1") 169 170 if rgc.allowCond && rand.Intn(1000) >= 500 { 171 b = b.Where(randCond(b.selects, 3)) 172 } 173 174 return b 175 } 176 177 func randUpdateByCondition(rgc *randGenConf) *Builder { 178 fields := randSelects() 179 180 times := rand.Intn(10) + 1 181 182 eqs := Eq{} 183 for i := 0; i < times; i++ { 184 eqs[fields[rand.Intn(len(fields))]] = randVal() 185 } 186 187 b := Update(eqs).From("table1") 188 189 if rgc.allowCond && rand.Intn(1000) >= 500 { 190 b.Where(randCond(fields, 3)) 191 } 192 193 return b 194 } 195 196 func randSelectByCondition(dialect string, rgc *randGenConf) *Builder { 197 var b *Builder 198 if rgc.allowSubQuery { 199 cpRgc := *rgc 200 cpRgc.allowSubQuery = false 201 b = Dialect(dialect).Select(randSelects()...).From(randQuery(dialect, &cpRgc), randTableName(0)) 202 } else { 203 b = Dialect(dialect).Select(randSelects()...).From(randTableName(0)) 204 } 205 if rgc.allowJoin { 206 b = randJoin(b, 3) 207 } 208 if rgc.allowCond && rand.Intn(1000) >= 500 { 209 b = b.Where(randCond(b.selects, 3)) 210 } 211 if rgc.allowLimit && rand.Intn(1000) >= 500 { 212 b = randLimit(b) 213 } 214 if rgc.allowOrderBy && rand.Intn(1000) >= 500 { 215 b = randOrderBy(b) 216 } 217 if rgc.allowHaving && rand.Intn(1000) >= 500 { 218 b = randHaving(b) 219 } 220 if rgc.allowGroupBy && rand.Intn(1000) >= 500 { 221 b = randGroupBy(b) 222 } 223 224 return b 225 } 226 227 func randDialect() string { 228 dialects := []string{MYSQL, ORACLE, MSSQL, SQLITE, POSTGRES} 229 230 return dialects[rand.Intn(len(dialects))] 231 } 232 233 func randSelects() []string { 234 if rand.Intn(1000) > 900 { 235 return []string{"*"} 236 } 237 238 rdx := rand.Intn(len(queryFields) / 2) 239 return queryFields[rdx:] 240 } 241 242 func randTableName(offset int) string { 243 return fmt.Sprintf("table%v", rand.Intn(10)+offset) 244 } 245 246 func randJoin(b *Builder, lessThan int) *Builder { 247 if lessThan <= 0 { 248 return b 249 } 250 251 times := rand.Intn(lessThan) 252 253 for i := 0; i < times; i++ { 254 tableName := randTableName(i * 10) 255 b = b.Join("", tableName, fmt.Sprintf("%v.id = %v.id", b.TableName(), tableName)) 256 } 257 258 return b 259 } 260 261 func randCond(selects []string, lessThan int) Cond { 262 if len(selects) <= 0 { 263 return nil 264 } 265 266 cond := NewCond() 267 268 times := rand.Intn(lessThan) 269 for i := 0; i < times; i++ { 270 cond = cond.And(Eq{selects[rand.Intn(len(selects))]: randVal()}) 271 } 272 273 return cond 274 } 275 276 func randLimit(b *Builder) *Builder { 277 r := rand.Intn(1000) + 1 278 if r > 500 { 279 return b.Limit(r, 1000) 280 } 281 return b.Limit(r) 282 } 283 284 func randOrderBy(b *Builder) *Builder { 285 return b.OrderBy(fmt.Sprintf("%v ASC", b.selects[rand.Intn(len(b.selects))])) 286 } 287 288 func randHaving(b *Builder) *Builder { 289 return b.OrderBy(fmt.Sprintf("%v = %v", b.selects[rand.Intn(len(b.selects))], randVal())) 290 } 291 292 func randGroupBy(b *Builder) *Builder { 293 return b.GroupBy(fmt.Sprintf("%v = %v", b.selects[rand.Intn(len(b.selects))], randVal())) 294 } 295 296 func randVal() interface{} { 297 return expectedValues[rand.Intn(len(expectedValues))] 298 }