From db2be9f119a979b934cefa674cefecbf27ab07ca Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Tue, 27 Mar 2012 12:19:39 -0700 Subject: [PATCH] skip pk row cache optimization if there's an order by clause display query plans for query_cache stats rowcache: limit size to 4k --- go/vt/sqlparser/execution.go | 24 +++++++++++++----------- go/vt/sqlparser/test/exec_cases.txt | 23 +++++++++++++++++++++++ go/vt/tabletserver/rowcache.go | 21 +++++++++++++++++++++ go/vt/tabletserver/schema_info.go | 13 ++++++++++++- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/go/vt/sqlparser/execution.go b/go/vt/sqlparser/execution.go index 7440fddefa..6279f2c7b7 100644 --- a/go/vt/sqlparser/execution.go +++ b/go/vt/sqlparser/execution.go @@ -265,26 +265,28 @@ func (self *Node) execAnalyzeSelect(getTable TableGetter) (plan *ExecPlan) { return plan } - if pkValues := getPKValues(conditions, tableInfo.Indexes[0]); pkValues != nil { - plan.PlanId = PLAN_SELECT_PK - plan.OuterQuery = self.GenerateSelectOuterQuery(tableInfo) - plan.PKValues = pkValues + // order + orders := self.At(SELECT_ORDER_OFFSET).execAnalyzeOrder() + if orders == nil { + plan.Reason = REASON_ORDER return plan } + if len(orders) == 0 { // Only do pk analysis if there's no order by clause + if pkValues := getPKValues(conditions, tableInfo.Indexes[0]); pkValues != nil { + plan.PlanId = PLAN_SELECT_PK + plan.OuterQuery = self.GenerateSelectOuterQuery(tableInfo) + plan.PKValues = pkValues + return plan + } + } + // TODO: Analyze hints to improve plan. if hasHints { plan.Reason = REASON_HAS_HINTS return plan } - // order - orders := self.At(SELECT_ORDER_OFFSET).execAnalyzeOrder() - if orders == nil { - plan.Reason = REASON_ORDER - return plan - } - plan.IndexUsed = getIndexMatch(conditions, orders, tableInfo.Indexes) if plan.IndexUsed == "" { plan.Reason = REASON_NOINDEX_MATCH diff --git a/go/vt/sqlparser/test/exec_cases.txt b/go/vt/sqlparser/test/exec_cases.txt index cd9a1bf532..432b112884 100644 --- a/go/vt/sqlparser/test/exec_cases.txt +++ b/go/vt/sqlparser/test/exec_cases.txt @@ -829,6 +829,29 @@ select * from a where eid between 1 and 2 and name='foo' "SetValue": null } +# order by (pk) +select * from a where eid=1 and id=1 order by name +{ + "PlanId": "SELECT_CACHE_RESULT", + "Reason": "PKINDEX", + "TableName": "a", + "FullQuery": "select * from a where eid = 1 and id = 1 order by name asc limit :_vtMaxResultSize", + "OuterQuery": "select eid, id, name, foo from a where eid = 1 and id = 1 order by name asc limit :_vtMaxResultSize", + "Subquery": null, + "IndexUsed": "PRIMARY", + "ColumnNumbers": [ + 0, + 1, + 2, + 3 + ], + "PKValues": null, + "SecondaryPKValues": null, + "SubqueryPKColumns": null, + "SetKey": "", + "SetValue": null +} + # order by select * from a where eid=1 order by name { diff --git a/go/vt/tabletserver/rowcache.go b/go/vt/tabletserver/rowcache.go index 43059838cc..3ee354f662 100644 --- a/go/vt/tabletserver/rowcache.go +++ b/go/vt/tabletserver/rowcache.go @@ -75,6 +75,11 @@ func (self *RowCache) Get(key string) (row []interface{}) { } func (self *RowCache) Set(key string, row []interface{}, readTime time.Time) { + // This value is hardcoded for now. + // We're assuming it's not worth caching rows that are too large. + if rowLen(row) > 4000 { + return + } conn := self.cachePool.Get() defer conn.Recycle() mkey := self.prefix + key @@ -117,3 +122,19 @@ func (self *RowCache) Delete(key string) { panic(NewTabletError(FATAL, "%s", err)) } } + +func rowLen(row []interface{}) int { + length := 0 + for _, v := range row { + if v == nil { + continue + } + switch col := v.(type) { + case string: + length += len(col) + case []byte: + length += len(col) + } + } + return length +} diff --git a/go/vt/tabletserver/schema_info.go b/go/vt/tabletserver/schema_info.go index 211304312c..08c4968cb3 100644 --- a/go/vt/tabletserver/schema_info.go +++ b/go/vt/tabletserver/schema_info.go @@ -36,6 +36,7 @@ import ( "code.google.com/p/vitess/go/relog" "code.google.com/p/vitess/go/vt/schema" "code.google.com/p/vitess/go/vt/sqlparser" + "encoding/json" "fmt" "net/http" "sync" @@ -202,8 +203,16 @@ func (self *SchemaInfo) ServeHTTP(response http.ResponseWriter, request *http.Re response.Write([]byte(fmt.Sprintf("Length: %d\n", len(keys)))) for _, v := range keys { response.Write([]byte(fmt.Sprintf("%s\n", v))) + if plan := self.getQuery(v); plan != nil { + if b, err := json.MarshalIndent(plan, "", " "); err != nil { + response.Write([]byte(err.Error())) + } else { + response.Write(b) + response.Write(([]byte)("\n\n")) + } + } } - } else { // tables + } else if request.URL.Path == "/debug/schema/tables" { response.Header().Set("Content-Type", "text/plain") self.mu.Lock() tstats := make(map[string]struct{ hits, absent, misses int64 }) @@ -224,5 +233,7 @@ func (self *SchemaInfo) ServeHTTP(response http.ResponseWriter, request *http.Re } fmt.Fprintf(response, "\"Totals\": {\"Hits\": %v, \"Absent\": %v, \"Misses\": %v}\n", totals.hits, totals.absent, totals.misses) response.Write([]byte("}\n")) + } else { + response.WriteHeader(http.StatusNotFound) } }