feat: optimize partition by tbname
This commit is contained in:
parent
aca91eb831
commit
896c1b3a6d
|
@ -52,7 +52,7 @@ typedef struct SExprNode {
|
||||||
SArray* pAssociation;
|
SArray* pAssociation;
|
||||||
} SExprNode;
|
} SExprNode;
|
||||||
|
|
||||||
typedef enum EColumnType { COLUMN_TYPE_COLUMN = 1, COLUMN_TYPE_TAG } EColumnType;
|
typedef enum EColumnType { COLUMN_TYPE_COLUMN = 1, COLUMN_TYPE_TAG, COLUMN_TYPE_TBNAME } EColumnType;
|
||||||
|
|
||||||
typedef struct SColumnNode {
|
typedef struct SColumnNode {
|
||||||
SExprNode node; // QUERY_NODE_COLUMN
|
SExprNode node; // QUERY_NODE_COLUMN
|
||||||
|
|
|
@ -1315,15 +1315,6 @@ static void destroyInsertParseContext(SInsertParseContext* pCxt) {
|
||||||
destroyBlockArrayList(pCxt->pVgDataBlocks);
|
destroyBlockArrayList(pCxt->pVgDataBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t checkSchemalessDb(SInsertParseContext* pCxt, char* pDbName) {
|
|
||||||
// SDbCfgInfo pInfo = {0};
|
|
||||||
// char fullName[TSDB_TABLE_FNAME_LEN];
|
|
||||||
// snprintf(fullName, sizeof(fullName), "%d.%s", pCxt->pComCxt->acctId, pDbName);
|
|
||||||
// CHECK_CODE(getDBCfg(pCxt, fullName, &pInfo));
|
|
||||||
// return pInfo.schemaless ? TSDB_CODE_SML_INVALID_DB_CONF : TSDB_CODE_SUCCESS;
|
|
||||||
return TSDB_CODE_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tb_name
|
// tb_name
|
||||||
// [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...)]
|
// [USING stb_name [(tag1_name, ...)] TAGS (tag1_value, ...)]
|
||||||
// [(field1_name, ...)]
|
// [(field1_name, ...)]
|
||||||
|
@ -1377,8 +1368,6 @@ static int32_t parseInsertBody(SInsertParseContext* pCxt) {
|
||||||
SName name;
|
SName name;
|
||||||
CHECK_CODE(createSName(&name, &tbnameToken, pCxt->pComCxt->acctId, pCxt->pComCxt->db, &pCxt->msg));
|
CHECK_CODE(createSName(&name, &tbnameToken, pCxt->pComCxt->acctId, pCxt->pComCxt->db, &pCxt->msg));
|
||||||
|
|
||||||
CHECK_CODE(checkSchemalessDb(pCxt, name.dbname));
|
|
||||||
|
|
||||||
tNameExtractFullName(&name, tbFName);
|
tNameExtractFullName(&name, tbFName);
|
||||||
CHECK_CODE(taosHashPut(pCxt->pTableNameHashObj, tbFName, strlen(tbFName), &name, sizeof(SName)));
|
CHECK_CODE(taosHashPut(pCxt->pTableNameHashObj, tbFName, strlen(tbFName), &name, sizeof(SName)));
|
||||||
char dbFName[TSDB_DB_FNAME_LEN];
|
char dbFName[TSDB_DB_FNAME_LEN];
|
||||||
|
|
|
@ -56,8 +56,12 @@ static EDealRes doRewriteExpr(SNode** pNode, void* pContext) {
|
||||||
pCol->node.resType = pToBeRewrittenExpr->resType;
|
pCol->node.resType = pToBeRewrittenExpr->resType;
|
||||||
strcpy(pCol->node.aliasName, pToBeRewrittenExpr->aliasName);
|
strcpy(pCol->node.aliasName, pToBeRewrittenExpr->aliasName);
|
||||||
strcpy(pCol->colName, ((SExprNode*)pExpr)->aliasName);
|
strcpy(pCol->colName, ((SExprNode*)pExpr)->aliasName);
|
||||||
if (QUERY_NODE_FUNCTION == nodeType(pExpr) && FUNCTION_TYPE_WSTARTTS == ((SFunctionNode*)pExpr)->funcType) {
|
if (QUERY_NODE_FUNCTION == nodeType(pExpr)) {
|
||||||
|
if (FUNCTION_TYPE_WSTARTTS == ((SFunctionNode*)pExpr)->funcType) {
|
||||||
pCol->colId = PRIMARYKEY_TIMESTAMP_COL_ID;
|
pCol->colId = PRIMARYKEY_TIMESTAMP_COL_ID;
|
||||||
|
} else if (FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pExpr)->funcType) {
|
||||||
|
pCol->colType = COLUMN_TYPE_TBNAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
nodesDestroyNode(*pNode);
|
nodesDestroyNode(*pNode);
|
||||||
*pNode = (SNode*)pCol;
|
*pNode = (SNode*)pCol;
|
||||||
|
|
|
@ -1042,7 +1042,7 @@ static int32_t smaOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan)
|
||||||
|
|
||||||
static EDealRes partTagsOptHasColImpl(SNode* pNode, void* pContext) {
|
static EDealRes partTagsOptHasColImpl(SNode* pNode, void* pContext) {
|
||||||
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
if (QUERY_NODE_COLUMN == nodeType(pNode)) {
|
||||||
if (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType) {
|
if (COLUMN_TYPE_TAG != ((SColumnNode*)pNode)->colType && COLUMN_TYPE_TBNAME != ((SColumnNode*)pNode)->colType) {
|
||||||
*(bool*)pContext = true;
|
*(bool*)pContext = true;
|
||||||
return DEAL_RES_END;
|
return DEAL_RES_END;
|
||||||
}
|
}
|
||||||
|
@ -1080,6 +1080,28 @@ static bool partTagsOptMayBeOptimized(SLogicNode* pNode) {
|
||||||
return !partTagsOptHasCol(partTagsGetPartKeys(pNode));
|
return !partTagsOptHasCol(partTagsGetPartKeys(pNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EDealRes partTagsOptRebuildTbanmeImpl(SNode** pNode, void* pContext) {
|
||||||
|
if (QUERY_NODE_COLUMN == nodeType(*pNode) && COLUMN_TYPE_TBNAME == ((SColumnNode*)*pNode)->colType) {
|
||||||
|
SFunctionNode* pFunc = (SFunctionNode*)nodesMakeNode(QUERY_NODE_FUNCTION);
|
||||||
|
if (NULL == pFunc) {
|
||||||
|
*(int32_t*)pContext = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
return DEAL_RES_ERROR;
|
||||||
|
}
|
||||||
|
strcpy(pFunc->functionName, "tbname");
|
||||||
|
pFunc->funcType = FUNCTION_TYPE_TBNAME;
|
||||||
|
nodesDestroyNode(*pNode);
|
||||||
|
*pNode = (SNode*)pFunc;
|
||||||
|
return DEAL_RES_IGNORE_CHILD;
|
||||||
|
}
|
||||||
|
return DEAL_RES_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t partTagsOptRebuildTbanme(SNodeList* pPartKeys) {
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
nodesRewriteExprs(pPartKeys, partTagsOptRebuildTbanmeImpl, &code);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
|
static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSubplan) {
|
||||||
SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, partTagsOptMayBeOptimized);
|
SLogicNode* pNode = optFindPossibleNode(pLogicSubplan->pNode, partTagsOptMayBeOptimized);
|
||||||
if (NULL == pNode) {
|
if (NULL == pNode) {
|
||||||
|
@ -1096,7 +1118,18 @@ static int32_t partTagsOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogicSub
|
||||||
nodesDestroyNode((SNode*)pNode);
|
nodesDestroyNode((SNode*)pNode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TSWAP(((SAggLogicNode*)pNode)->pGroupKeys, pScan->pPartTags);
|
SNode* pGroupKey = NULL;
|
||||||
|
FOREACH(pGroupKey, ((SAggLogicNode*)pNode)->pGroupKeys) {
|
||||||
|
code = nodesListMakeStrictAppend(
|
||||||
|
&pScan->pPartTags, nodesCloneNode(nodesListGetNode(((SGroupingSetNode*)pGroupKey)->pParameterList, 0)));
|
||||||
|
if (TSDB_CODE_SUCCESS != code) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DESTORY_LIST(((SAggLogicNode*)pNode)->pGroupKeys);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = partTagsOptRebuildTbanme(pScan->pPartTags);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -1184,7 +1217,7 @@ static const SOptimizeRule optimizeRuleSet[] = {
|
||||||
{.pName = "ConditionPushDown", .optimizeFunc = cpdOptimize},
|
{.pName = "ConditionPushDown", .optimizeFunc = cpdOptimize},
|
||||||
{.pName = "OrderByPrimaryKey", .optimizeFunc = opkOptimize},
|
{.pName = "OrderByPrimaryKey", .optimizeFunc = opkOptimize},
|
||||||
{.pName = "SmaIndex", .optimizeFunc = smaOptimize},
|
{.pName = "SmaIndex", .optimizeFunc = smaOptimize},
|
||||||
{.pName = "PartitionByTags", .optimizeFunc = partTagsOptimize},
|
{.pName = "PartitionTags", .optimizeFunc = partTagsOptimize},
|
||||||
{.pName = "EliminateProject", .optimizeFunc = eliminateProjOptimize}
|
{.pName = "EliminateProject", .optimizeFunc = eliminateProjOptimize}
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -380,6 +380,7 @@ static int32_t stbSplCreateExchangeNode(SSplitContext* pCxt, SLogicNode* pParent
|
||||||
SExchangeLogicNode* pExchange = NULL;
|
SExchangeLogicNode* pExchange = NULL;
|
||||||
int32_t code = splCreateExchangeNode(pCxt, pPartChild, &pExchange);
|
int32_t code = splCreateExchangeNode(pCxt, pPartChild, &pExchange);
|
||||||
if (TSDB_CODE_SUCCESS == code) {
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
pExchange->node.pParent = pParent;
|
||||||
code = nodesListMakeAppend(&pParent->pChildren, (SNode*)pExchange);
|
code = nodesListMakeAppend(&pParent->pChildren, (SNode*)pExchange);
|
||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
|
@ -484,7 +485,27 @@ static int32_t stbSplSplitSession(SSplitContext* pCxt, SStableSplitInfo* pInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t stbSplSplitWindowNode(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
|
static SNodeList* stbSplGetPartKeys(SLogicNode* pNode) {
|
||||||
|
if (QUERY_NODE_LOGIC_PLAN_SCAN == nodeType(pNode)) {
|
||||||
|
return ((SScanLogicNode*)pNode)->pPartTags;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool stbSplIsPartTbanme(SNodeList* pPartKeys) {
|
||||||
|
if (NULL == pPartKeys || 1 != LIST_LENGTH(pPartKeys)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SNode* pPartKey = nodesListGetNode(pPartKeys, 0);
|
||||||
|
return QUERY_NODE_FUNCTION == nodeType(pPartKey) && FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pPartKey)->funcType;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool stbSplIsMultiTableWinodw(SWindowLogicNode* pWindow) {
|
||||||
|
return stbSplIsPartTbanme(stbSplGetPartKeys((SLogicNode*)nodesListGetNode(pWindow->node.pChildren, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t stbSplSplitWindowForMergeTable(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
|
||||||
switch (((SWindowLogicNode*)pInfo->pSplitNode)->winType) {
|
switch (((SWindowLogicNode*)pInfo->pSplitNode)->winType) {
|
||||||
case WINDOW_TYPE_INTERVAL:
|
case WINDOW_TYPE_INTERVAL:
|
||||||
return stbSplSplitInterval(pCxt, pInfo);
|
return stbSplSplitInterval(pCxt, pInfo);
|
||||||
|
@ -496,6 +517,34 @@ static int32_t stbSplSplitWindowNode(SSplitContext* pCxt, SStableSplitInfo* pInf
|
||||||
return TSDB_CODE_PLAN_INTERNAL_ERROR;
|
return TSDB_CODE_PLAN_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t stbSplSplitWindowForMultiTable(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
|
||||||
|
if (pCxt->pPlanCxt->streamQuery) {
|
||||||
|
SPLIT_FLAG_SET_MASK(pInfo->pSubplan->splitFlag, SPLIT_FLAG_STABLE_SPLIT);
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SExchangeLogicNode* pExchange = NULL;
|
||||||
|
int32_t code = splCreateExchangeNode(pCxt, pInfo->pSplitNode, &pExchange);
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = replaceLogicNode(pInfo->pSubplan, pInfo->pSplitNode, (SLogicNode*)pExchange);
|
||||||
|
}
|
||||||
|
if (TSDB_CODE_SUCCESS == code) {
|
||||||
|
code = nodesListMakeStrictAppend(&pInfo->pSubplan->pChildren,
|
||||||
|
(SNode*)splCreateScanSubplan(pCxt, pInfo->pSplitNode, SPLIT_FLAG_STABLE_SPLIT));
|
||||||
|
}
|
||||||
|
pInfo->pSubplan->subplanType = SUBPLAN_TYPE_MERGE;
|
||||||
|
++(pCxt->groupId);
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t stbSplSplitWindowNode(SSplitContext* pCxt, SStableSplitInfo* pInfo) {
|
||||||
|
if (stbSplIsMultiTableWinodw((SWindowLogicNode*)pInfo->pSplitNode)) {
|
||||||
|
return stbSplSplitWindowForMultiTable(pCxt, pInfo);
|
||||||
|
} else {
|
||||||
|
return stbSplSplitWindowForMergeTable(pCxt, pInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t stbSplCreatePartAggNode(SAggLogicNode* pMergeAgg, SLogicNode** pOutput) {
|
static int32_t stbSplCreatePartAggNode(SAggLogicNode* pMergeAgg, SLogicNode** pOutput) {
|
||||||
SNodeList* pFunc = pMergeAgg->pAggFuncs;
|
SNodeList* pFunc = pMergeAgg->pAggFuncs;
|
||||||
pMergeAgg->pAggFuncs = NULL;
|
pMergeAgg->pAggFuncs = NULL;
|
||||||
|
|
|
@ -37,7 +37,9 @@ TEST_F(PlanOtherTest, createStream) {
|
||||||
TEST_F(PlanOtherTest, createStreamUseSTable) {
|
TEST_F(PlanOtherTest, createStreamUseSTable) {
|
||||||
useDb("root", "test");
|
useDb("root", "test");
|
||||||
|
|
||||||
run("create stream if not exists s1 as select count(*) from st1 interval(10s)");
|
run("CREATE STREAM IF NOT EXISTS s1 as SELECT COUNT(*) FROM st1 INTERVAL(10s)");
|
||||||
|
|
||||||
|
run("CREATE STREAM IF NOT EXISTS s1 as SELECT COUNT(*) FROM st1 PARTITION BY TBNAME INTERVAL(10s)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PlanOtherTest, createSmaIndex) {
|
TEST_F(PlanOtherTest, createSmaIndex) {
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#define FREE_HASH_NODE(_fp, _n) \
|
#define FREE_HASH_NODE(_fp, _n) \
|
||||||
do { \
|
do { \
|
||||||
if (_fp != NULL) { \
|
if (_fp != NULL) { \
|
||||||
(_fp)(_n); \
|
(_fp)(GET_HASH_NODE_DATA(_n)); \
|
||||||
} \
|
} \
|
||||||
taosMemoryFreeClear(_n); \
|
taosMemoryFreeClear(_n); \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
Loading…
Reference in New Issue