diff --git a/pkg/query-service/app/traces/v3/query_builder.go b/pkg/query-service/app/traces/v3/query_builder.go index 49572241d9..e8142eeead 100644 --- a/pkg/query-service/app/traces/v3/query_builder.go +++ b/pkg/query-service/app/traces/v3/query_builder.go @@ -102,7 +102,7 @@ func getSelectLabels(aggregatorOperator v3.AggregateOperator, groupBy []v3.Attri } else { for _, tag := range groupBy { filterName := getColumnName(tag, keys) - selectLabels += fmt.Sprintf(", %s as `%s`", filterName, tag.Key) + selectLabels += fmt.Sprintf(" %s as `%s`,", filterName, tag.Key) } } return selectLabels @@ -235,14 +235,26 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str having = " having " + having } - // Select the aggregate value for interval - queryTmpl := - "SELECT toStartOfInterval(timestamp, INTERVAL %d SECOND) AS ts" + selectLabels + - ", %s as value " + - "from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME + - " where " + spanIndexTableTimeFilter + "%s " + - "group by %s%s " + - "order by %s" + var queryTmpl string + + if panelType == v3.PanelTypeTable { + queryTmpl = + "SELECT now() as ts," + selectLabels + + " %s as value " + + "from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME + + " where " + spanIndexTableTimeFilter + "%s" + + "%s%s" + + "%s" + } else if panelType == v3.PanelTypeGraph || panelType == v3.PanelTypeValue { + // Select the aggregate value for interval + queryTmpl = + fmt.Sprintf("SELECT toStartOfInterval(timestamp, INTERVAL %d SECOND) AS ts,", step) + selectLabels + + " %s as value " + + "from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME + + " where " + spanIndexTableTimeFilter + "%s" + + "%s%s" + + "%s" + } emptyValuesInGroupByFilter, err := handleEmptyValuesInGroupBy(keys, mq.GroupBy) if err != nil { @@ -250,10 +262,15 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str } filterSubQuery += emptyValuesInGroupByFilter - groupBy := groupByAttributeKeyTags(keys, mq.GroupBy...) + groupBy := groupByAttributeKeyTags(panelType, mq.GroupBy...) + if groupBy != "" { + groupBy = " group by " + groupBy + } enrichedOrderBy := enrichOrderBy(mq.OrderBy, keys) orderBy := orderByAttributeKeyTags(panelType, enrichedOrderBy, mq.GroupBy, keys) - + if orderBy != "" { + orderBy = " order by " + orderBy + } aggregationKey := "" if mq.AggregateAttribute.Key != "" { aggregationKey = getColumnName(mq.AggregateAttribute, keys) @@ -266,7 +283,7 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str v3.AggregateOperatorRateMin, v3.AggregateOperatorRate: op := fmt.Sprintf("%s(%s)/%d", aggregateOperatorToSQLFunc[mq.AggregateOperator], aggregationKey, step) - query := fmt.Sprintf(queryTmpl, step, op, filterSubQuery, groupBy, having, orderBy) + query := fmt.Sprintf(queryTmpl, op, filterSubQuery, groupBy, having, orderBy) return query, nil case v3.AggregateOperatorP05, @@ -279,11 +296,11 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str v3.AggregateOperatorP95, v3.AggregateOperatorP99: op := fmt.Sprintf("quantile(%v)(%s)", aggregateOperatorToPercentile[mq.AggregateOperator], aggregationKey) - query := fmt.Sprintf(queryTmpl, step, op, filterSubQuery, groupBy, having, orderBy) + query := fmt.Sprintf(queryTmpl, op, filterSubQuery, groupBy, having, orderBy) return query, nil case v3.AggregateOperatorAvg, v3.AggregateOperatorSum, v3.AggregateOperatorMin, v3.AggregateOperatorMax: op := fmt.Sprintf("%s(%s)", aggregateOperatorToSQLFunc[mq.AggregateOperator], aggregationKey) - query := fmt.Sprintf(queryTmpl, step, op, filterSubQuery, groupBy, having, orderBy) + query := fmt.Sprintf(queryTmpl, op, filterSubQuery, groupBy, having, orderBy) return query, nil case v3.AggregateOperatorCount: if mq.AggregateAttribute.Key != "" { @@ -299,11 +316,11 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str } } op := "toFloat64(count())" - query := fmt.Sprintf(queryTmpl, step, op, filterSubQuery, groupBy, having, orderBy) + query := fmt.Sprintf(queryTmpl, op, filterSubQuery, groupBy, having, orderBy) return query, nil case v3.AggregateOperatorCountDistinct: op := fmt.Sprintf("toFloat64(count(distinct(%s)))", aggregationKey) - query := fmt.Sprintf(queryTmpl, step, op, filterSubQuery, groupBy, having, orderBy) + query := fmt.Sprintf(queryTmpl, op, filterSubQuery, groupBy, having, orderBy) return query, nil case v3.AggregateOperatorNoOp: var query string @@ -319,7 +336,7 @@ func buildTracesQuery(start, end, step int64, mq *v3.BuilderQuery, tableName str return "", fmt.Errorf("select columns cannot be empty for panelType %s", panelType) } selectColumns := getSelectColumns(mq.SelectColumns, keys) - queryNoOpTmpl := fmt.Sprintf("SELECT timestamp as timestamp_datetime, spanID, traceID, "+"%s ", selectColumns) + "from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME + " where %s %s" + " order by %s" + queryNoOpTmpl := fmt.Sprintf("SELECT timestamp as timestamp_datetime, spanID, traceID, "+"%s ", selectColumns) + "from " + constants.SIGNOZ_TRACE_DBNAME + "." + constants.SIGNOZ_SPAN_INDEX_TABLENAME + " where %s %s" + "%s" query = fmt.Sprintf(queryNoOpTmpl, spanIndexTableTimeFilter, filterSubQuery, orderBy) } else { return "", fmt.Errorf("unsupported aggregate operator %s for panelType %s", mq.AggregateOperator, panelType) @@ -350,17 +367,19 @@ func enrichOrderBy(items []v3.OrderBy, keys map[string]v3.AttributeKey) []v3.Ord // groupBy returns a string of comma separated tags for group by clause // `ts` is always added to the group by clause -func groupBy(tags ...string) string { - tags = append(tags, "ts") +func groupBy(panelType v3.PanelType, tags ...string) string { + if panelType == v3.PanelTypeGraph || panelType == v3.PanelTypeValue { + tags = append(tags, "ts") + } return strings.Join(tags, ",") } -func groupByAttributeKeyTags(keys map[string]v3.AttributeKey, tags ...v3.AttributeKey) string { +func groupByAttributeKeyTags(panelType v3.PanelType, tags ...v3.AttributeKey) string { groupTags := []string{} for _, tag := range tags { groupTags = append(groupTags, fmt.Sprintf("`%s`", tag.Key)) } - return groupBy(groupTags...) + return groupBy(panelType, groupTags...) } // orderBy returns a string of comma separated tags for order by clause @@ -403,7 +422,7 @@ func orderBy(panelType v3.PanelType, items []v3.OrderBy, tags []string, keys map if !addedToOrderBy[item.ColumnName] { attr := v3.AttributeKey{Key: item.ColumnName, DataType: item.DataType, Type: item.Type, IsColumn: item.IsColumn} name := getColumnName(attr, keys) - + if item.IsColumn { orderBy = append(orderBy, fmt.Sprintf("`%s` %s", name, item.Order)) } else { @@ -424,7 +443,7 @@ func orderByAttributeKeyTags(panelType v3.PanelType, items []v3.OrderBy, tags [] if panelType == v3.PanelTypeList && len(orderByArray) == 0 { orderByArray = append(orderByArray, constants.TIMESTAMP+" DESC") - } else if panelType == v3.PanelTypeGraph || panelType == v3.PanelTypeTable { + } else if panelType == v3.PanelTypeGraph || panelType == v3.PanelTypeValue { orderByArray = append(orderByArray, "ts") } diff --git a/pkg/query-service/app/traces/v3/query_builder_test.go b/pkg/query-service/app/traces/v3/query_builder_test.go index 023a636d12..7ec3fa49f7 100644 --- a/pkg/query-service/app/traces/v3/query_builder_test.go +++ b/pkg/query-service/app/traces/v3/query_builder_test.go @@ -216,13 +216,13 @@ var testGetSelectLabelsData = []struct { Name: "select keys for groupBy attribute", AggregateOperator: v3.AggregateOperatorCount, GroupByTags: []v3.AttributeKey{{Key: "user.name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}}, - SelectLabels: ", stringTagMap['user.name'] as `user.name`", + SelectLabels: " stringTagMap['user.name'] as `user.name`,", }, { Name: "select keys for groupBy resource", AggregateOperator: v3.AggregateOperatorCount, GroupByTags: []v3.AttributeKey{{Key: "user.name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource}}, - SelectLabels: ", resourceTagsMap['user.name'] as `user.name`", + SelectLabels: " resourceTagsMap['user.name'] as `user.name`,", }, { Name: "select keys for groupBy attribute and resource", @@ -231,13 +231,13 @@ var testGetSelectLabelsData = []struct { {Key: "user.name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeResource}, {Key: "host", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, }, - SelectLabels: ", resourceTagsMap['user.name'] as `user.name`, stringTagMap['host'] as `host`", + SelectLabels: " resourceTagsMap['user.name'] as `user.name`, stringTagMap['host'] as `host`,", }, { Name: "select keys for groupBy fixed columns", AggregateOperator: v3.AggregateOperatorCount, GroupByTags: []v3.AttributeKey{{Key: "host", IsColumn: true, DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}}, - SelectLabels: ", host as `host`", + SelectLabels: " host as `host`,", }, } @@ -956,6 +956,77 @@ var testBuildTracesQueryData = []struct { "AND stringTagMap['method'] = 'GET' group by ts having value > 10 order by ts", PanelType: v3.PanelTypeGraph, }, + { + Name: "Test count with having clause and filters", + Start: 1680066360726210000, + End: 1680066458000000000, + Step: 60, + BuilderQuery: &v3.BuilderQuery{ + QueryName: "A", + AggregateAttribute: v3.AttributeKey{Key: "name", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, + AggregateOperator: v3.AggregateOperatorCount, + Expression: "A", + Filters: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{ + {Key: v3.AttributeKey{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}, Value: "GET", Operator: "="}, + }, + }, + Having: []v3.Having{ + { + ColumnName: "name", + Operator: ">", + Value: 10, + }, + }, + }, + TableName: "signoz_traces.distributed_signoz_index_v2", + ExpectedQuery: "SELECT toStartOfInterval(timestamp, INTERVAL 60 SECOND) AS ts, toFloat64(count()) as value" + + " from signoz_traces.distributed_signoz_index_v2 where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " + + "AND stringTagMap['method'] = 'GET' AND has(stringTagMap, 'name') group by ts having value > 10 order by ts", + PanelType: v3.PanelTypeValue, + }, + { + Name: "Test aggregate PXX", + Start: 1680066360726210000, + End: 1680066458000000000, + Step: 60, + BuilderQuery: &v3.BuilderQuery{ + QueryName: "A", + AggregateAttribute: v3.AttributeKey{Key: "durationNano", IsColumn: true, DataType: v3.AttributeKeyDataTypeFloat64, Type: v3.AttributeKeyTypeTag}, + AggregateOperator: v3.AggregateOperatorP05, + Expression: "A", + Filters: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{}}, + GroupBy: []v3.AttributeKey{{Key: "method", DataType: v3.AttributeKeyDataTypeString, Type: v3.AttributeKeyTypeTag}}, + OrderBy: []v3.OrderBy{{ColumnName: "method", Order: "ASC"}}, + }, + TableName: "signoz_traces.distributed_signoz_index_v2", + ExpectedQuery: "SELECT now() as ts, stringTagMap['method'] as `method`, " + + "quantile(0.05)(durationNano) as value " + + "from signoz_traces.distributed_signoz_index_v2 " + + "where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000') " + + "AND has(stringTagMap, 'method') group by `method` " + + "order by `method` ASC", + PanelType: v3.PanelTypeTable, + }, + { + Name: "Test aggregate PXX", + Start: 1680066360726210000, + End: 1680066458000000000, + Step: 60, + BuilderQuery: &v3.BuilderQuery{ + QueryName: "A", + AggregateAttribute: v3.AttributeKey{Key: "durationNano", IsColumn: true, DataType: v3.AttributeKeyDataTypeFloat64, Type: v3.AttributeKeyTypeTag}, + AggregateOperator: v3.AggregateOperatorP05, + Expression: "A", + Filters: &v3.FilterSet{Operator: "AND", Items: []v3.FilterItem{}}, + GroupBy: []v3.AttributeKey{}, + OrderBy: []v3.OrderBy{}, + }, + TableName: "signoz_traces.distributed_signoz_index_v2", + ExpectedQuery: "SELECT now() as ts, quantile(0.05)(durationNano) as value " + + "from signoz_traces.distributed_signoz_index_v2 " + + "where (timestamp >= '1680066360726210000' AND timestamp <= '1680066458000000000')", + PanelType: v3.PanelTypeTable, + }, { Name: "Test Noop list view", Start: 1680066360726210000,