mirror of https://gitee.com/bigwinds/arangodb
JAN: more optimisation
This commit is contained in:
parent
496a55cdb1
commit
d913bd95b1
|
@ -208,6 +208,32 @@ QL_ast_node_type_group_e QLAstNodeGetTypeGroup (const QL_ast_node_type_e type) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the reverse of a relational operator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QL_ast_node_type_e QLAstNodeGetReversedRelationalOperator (const QL_ast_node_type_e type) {
|
||||
if (type == QLNodeBinaryOperatorIdentical ||
|
||||
type == QLNodeBinaryOperatorEqual ||
|
||||
type == QLNodeBinaryOperatorUnidentical ||
|
||||
type == QLNodeBinaryOperatorUnequal) {
|
||||
return type;
|
||||
}
|
||||
if (type == QLNodeBinaryOperatorLess) {
|
||||
return QLNodeBinaryOperatorGreaterEqual;
|
||||
}
|
||||
if (type == QLNodeBinaryOperatorLessEqual) {
|
||||
return QLNodeBinaryOperatorGreater;
|
||||
}
|
||||
if (type == QLNodeBinaryOperatorGreater) {
|
||||
return QLNodeBinaryOperatorLessEqual;
|
||||
}
|
||||
if (type == QLNodeBinaryOperatorGreaterEqual) {
|
||||
return QLNodeBinaryOperatorLess;
|
||||
}
|
||||
assert(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the label string for a unary operator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -169,6 +169,12 @@ const char* QLAstNodeGetName (const QL_ast_node_type_e);
|
|||
|
||||
QL_ast_node_type_group_e QLAstNodeGetTypeGroup (const QL_ast_node_type_e);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the reverse of a relational operator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QL_ast_node_type_e QLAstNodeGetReversedRelationalOperator (const QL_ast_node_type_e);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the label string for a unary operator
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -158,6 +158,22 @@ bool QLAstQueryIsValidAlias (QL_ast_query_t* query, const char* alias) {
|
|||
return (0 != TRI_LookupByKeyAssociativePointer(&query->_from._collections, alias));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Return the collection name for its alias
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* QLAstQueryGetCollectionNameForAlias (QL_ast_query_t* query,
|
||||
const char* alias) {
|
||||
QL_ast_query_collection_t* collection;
|
||||
|
||||
collection = (QL_ast_query_collection_t*)
|
||||
TRI_LookupByKeyAssociativePointer(&query->_from._collections, alias);
|
||||
if (!collection) {
|
||||
return NULL;
|
||||
}
|
||||
return collection->_name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Add a collection to the query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -214,6 +214,12 @@ void QLAstQueryAddRefCount (QL_ast_query_t*, const char*);
|
|||
|
||||
bool QLAstQueryIsValidAlias (QL_ast_query_t*, const char*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Return the collection name for its alias
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char* QLAstQueryGetCollectionNameForAlias (QL_ast_query_t*, const char*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Add a collection to the query
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
143
QL/optimize.c
143
QL/optimize.c
|
@ -208,6 +208,46 @@ double QLOptimizeGetDouble (const QL_ast_node_t const* node) {
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check if a document declaration is static or dynamic
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool QLOptimizeIsStaticDocument (QL_ast_node_t* node) {
|
||||
bool result;
|
||||
|
||||
if (node->_next) {
|
||||
while (node->_next) {
|
||||
result = QLOptimizeIsStaticDocument(node->_next);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
node = node->_next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (node->_lhs) {
|
||||
result = QLOptimizeIsStaticDocument(node->_lhs);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (node->_rhs) {
|
||||
result = QLOptimizeIsStaticDocument(node->_rhs);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (node->_type == QLNodeReferenceCollectionAlias ||
|
||||
node->_type == QLNodeControlFunctionCall ||
|
||||
node->_type == QLNodeControlTernary ||
|
||||
node->_type == QLNodeContainerMemberAccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief convert a node to a null value node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -870,6 +910,10 @@ void QLOptimizeFreeRangeVector (TRI_vector_pointer_t* vector) {
|
|||
if (range->_field) {
|
||||
TRI_Free(range->_field);
|
||||
}
|
||||
|
||||
if (range->_refValue._field) {
|
||||
TRI_FreeString(range->_refValue._field);
|
||||
}
|
||||
TRI_Free(range);
|
||||
}
|
||||
|
||||
|
@ -922,9 +966,20 @@ static TRI_vector_pointer_t* QLOptimizeCombineRanges (const QL_ast_node_type_e t
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
previous = QLOptimizeGetRangeByHash(range->_hash, vector);
|
||||
if (type == QLNodeBinaryOperatorOr) {
|
||||
// only use logical || operator for same field. if field name differs, an ||
|
||||
// effectively kills all ranges
|
||||
if (vector->_length >0 && !previous) {
|
||||
QLOptimizeFreeRangeVector(vector);
|
||||
TRI_InitVectorPointer(vector);
|
||||
goto EXIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (!previous) {
|
||||
// push range on stack
|
||||
// push range into result vector
|
||||
TRI_PushBackVectorPointer(vector, range);
|
||||
|
||||
// remove range from original vector to avoid double freeing
|
||||
|
@ -1298,6 +1353,7 @@ static QL_optimize_range_t* QLOptimizeCreateRange (QL_ast_node_t* memberNode,
|
|||
QL_optimize_range_t* range;
|
||||
TRI_string_buffer_t* name;
|
||||
QL_ast_node_t* lhs;
|
||||
QL_javascript_conversion_t* documentJs;
|
||||
|
||||
// get the field name
|
||||
name = QLOptimizeGetMemberNameString(memberNode, false);
|
||||
|
@ -1313,6 +1369,9 @@ static QL_optimize_range_t* QLOptimizeCreateRange (QL_ast_node_t* memberNode,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
range->_refValue._field = NULL;
|
||||
range->_refValue._collection = NULL;
|
||||
|
||||
// get value
|
||||
if (valueNode->_type == QLNodeValueNumberDouble ||
|
||||
valueNode->_type == QLNodeValueNumberDoubleString) {
|
||||
|
@ -1322,7 +1381,13 @@ static QL_optimize_range_t* QLOptimizeCreateRange (QL_ast_node_t* memberNode,
|
|||
else if (valueNode->_type == QLNodeValueString) {
|
||||
// range is of type string
|
||||
range->_valueType = RANGE_TYPE_STRING;
|
||||
}
|
||||
}
|
||||
else if (valueNode->_type == QLNodeValueDocument) {
|
||||
range->_valueType = RANGE_TYPE_JSON;
|
||||
}
|
||||
else if (valueNode->_type == QLNodeContainerMemberAccess) {
|
||||
range->_valueType = RANGE_TYPE_FIELD;
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
}
|
||||
|
@ -1340,14 +1405,37 @@ static QL_optimize_range_t* QLOptimizeCreateRange (QL_ast_node_t* memberNode,
|
|||
if (type == QLNodeBinaryOperatorIdentical ||
|
||||
type == QLNodeBinaryOperatorEqual) {
|
||||
// === and == , range is [ value (inc) ... value (inc) ]
|
||||
if (range->_valueType == RANGE_TYPE_DOUBLE) {
|
||||
if (range->_valueType == RANGE_TYPE_FIELD) {
|
||||
range->_refValue._collection =
|
||||
((QL_ast_node_t*) valueNode->_lhs)->_value._stringValue;
|
||||
name = QLOptimizeGetMemberNameString(valueNode, false);
|
||||
if (name) {
|
||||
range->_refValue._field = TRI_DuplicateString(name->_buffer);
|
||||
TRI_FreeStringBuffer(name);
|
||||
TRI_Free(name);
|
||||
}
|
||||
}
|
||||
else if (range->_valueType == RANGE_TYPE_DOUBLE) {
|
||||
range->_minValue._doubleValue = QLOptimizeGetDouble(valueNode);
|
||||
range->_maxValue._doubleValue = range->_minValue._doubleValue;
|
||||
}
|
||||
else if (range->_valueType == RANGE_TYPE_STRING) {
|
||||
else if (range->_valueType == RANGE_TYPE_STRING) {
|
||||
range->_minValue._stringValue = valueNode->_value._stringValue;
|
||||
range->_maxValue._stringValue = range->_minValue._stringValue;
|
||||
}
|
||||
else if (range->_valueType == RANGE_TYPE_JSON) {
|
||||
documentJs = QLJavascripterInit();
|
||||
if (!documentJs) {
|
||||
TRI_FreeStringBuffer(name);
|
||||
TRI_Free(name);
|
||||
TRI_Free(range);
|
||||
return NULL;
|
||||
}
|
||||
QLJavascripterConvert(documentJs, valueNode);
|
||||
range->_minValue._stringValue = documentJs->_buffer->_buffer;
|
||||
range->_maxValue._stringValue = range->_minValue._stringValue;
|
||||
QLJavascripterFree(documentJs);
|
||||
}
|
||||
range->_minStatus = RANGE_VALUE_INCLUDED;
|
||||
range->_maxStatus = RANGE_VALUE_INCLUDED;
|
||||
}
|
||||
|
@ -1449,19 +1537,43 @@ TRI_vector_pointer_t* QLOptimizeCondition (QL_ast_node_t* node) {
|
|||
type == QLNodeBinaryOperatorLessEqual ||
|
||||
type == QLNodeBinaryOperatorGreaterEqual) {
|
||||
// comparison operator
|
||||
|
||||
if (lhs->_type == QLNodeContainerMemberAccess &&
|
||||
rhs->_type == QLNodeContainerMemberAccess) {
|
||||
// collection.attribute relop collection.attribute
|
||||
return QLOptimizeMergeRangeVectors(
|
||||
QLOptimizeCreateRangeVector(QLOptimizeCreateRange(lhs, rhs, type)),
|
||||
QLOptimizeCreateRangeVector(QLOptimizeCreateRange(rhs, lhs, type))
|
||||
);
|
||||
}
|
||||
else if (lhs->_type == QLNodeContainerMemberAccess &&
|
||||
(type == QLNodeBinaryOperatorIdentical ||
|
||||
type == QLNodeBinaryOperatorEqual) &&
|
||||
rhs->_type == QLNodeValueDocument &&
|
||||
QLOptimizeIsStaticDocument(rhs)) {
|
||||
// collection.attribute == document
|
||||
return QLOptimizeCreateRangeVector(QLOptimizeCreateRange(lhs, rhs, type));
|
||||
}
|
||||
else if (lhs->_type == QLNodeContainerMemberAccess &&
|
||||
(rhs->_type == QLNodeValueNumberDouble ||
|
||||
rhs->_type == QLNodeValueNumberDoubleString ||
|
||||
rhs->_type == QLNodeValueString)) {
|
||||
// collection.attrbiute relop value
|
||||
// collection.attribute relop value
|
||||
return QLOptimizeCreateRangeVector(QLOptimizeCreateRange(lhs, rhs, type));
|
||||
}
|
||||
else if (rhs->_type == QLNodeContainerMemberAccess &&
|
||||
(type == QLNodeBinaryOperatorIdentical ||
|
||||
type == QLNodeBinaryOperatorEqual) &&
|
||||
lhs->_type == QLNodeValueDocument &&
|
||||
QLOptimizeIsStaticDocument(lhs)) {
|
||||
// document == collection.attribute
|
||||
return QLOptimizeCreateRangeVector(QLOptimizeCreateRange(rhs, lhs, type));
|
||||
} else if (rhs->_type == QLNodeContainerMemberAccess &&
|
||||
(lhs->_type == QLNodeValueNumberDouble ||
|
||||
lhs->_type == QLNodeValueNumberDoubleString ||
|
||||
lhs->_type == QLNodeValueString)) {
|
||||
lhs->_type == QLNodeValueString)) {
|
||||
// value relop collection.attrbiute
|
||||
return QLOptimizeCreateRangeVector(QLOptimizeCreateRange(rhs, lhs, type));
|
||||
return QLOptimizeCreateRangeVector(
|
||||
QLOptimizeCreateRange(rhs, lhs, QLAstNodeGetReversedRelationalOperator(type)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1555,22 +1667,25 @@ void QLOptimizeDetermineIndexes (QL_ast_query_t* query) {
|
|||
TRI_index_definition_t* indexDefinition;
|
||||
QL_ast_node_t* node;
|
||||
char* collectionName;
|
||||
char* alias;
|
||||
size_t i, j, k, matches;
|
||||
size_t count = 0;
|
||||
|
||||
return;
|
||||
node = (QL_ast_node_t*) query->_from._base->_next;
|
||||
|
||||
assert(node != 0);
|
||||
|
||||
|
||||
// enum all collections used in query
|
||||
while (node != 0) {
|
||||
ranges = 0;
|
||||
if (count++ == 0) {
|
||||
collectionName = ((QL_ast_node_t*) node->_lhs)->_value._stringValue;
|
||||
alias = ((QL_ast_node_t*) node->_rhs)->_value._stringValue;
|
||||
ranges = QLOptimizeCondition(query->_where._base);
|
||||
}
|
||||
else {
|
||||
collectionName = ((QL_ast_node_t*) ((QL_ast_node_t*) node->_lhs)->_lhs)->_value._stringValue;
|
||||
alias = ((QL_ast_node_t*) ((QL_ast_node_t*) node->_lhs)->_rhs)->_value._stringValue;
|
||||
}
|
||||
|
||||
// accessType = TABLE_SCAN;
|
||||
|
@ -1578,6 +1693,7 @@ return;
|
|||
if (ranges) {
|
||||
indexDefinitions = TRI_GetCollectionIndexes(query->_vocbase, collectionName);
|
||||
|
||||
// enum all indexes
|
||||
for (i = 0; i < indexDefinitions._length; i++) {
|
||||
indexDefinition = (TRI_index_definition_t*) indexDefinitions._buffer[i];
|
||||
|
||||
|
@ -1585,8 +1701,8 @@ return;
|
|||
for (j = 0 ; j < indexDefinition->_fields._length; j++) {
|
||||
for (k = 0; k < ranges->_length; k++) {
|
||||
range = (QL_optimize_range_t*) ranges->_buffer[k];
|
||||
// check if collection is the same
|
||||
if (strcmp(range->_collection, collectionName) != 0) {
|
||||
// check if collection name matches
|
||||
if (strcmp(range->_collection, alias) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1606,7 +1722,8 @@ return;
|
|||
range->_minValue._doubleValue != range->_maxValue._doubleValue) {
|
||||
continue;
|
||||
}
|
||||
if (range->_valueType == RANGE_TYPE_STRING &&
|
||||
if ((range->_valueType == RANGE_TYPE_STRING ||
|
||||
range->_valueType == RANGE_TYPE_JSON) &&
|
||||
strcmp(range->_minValue._stringValue, range->_maxValue._stringValue) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "QL/ast-query.h"
|
||||
#include "QL/parser-context.h"
|
||||
#include "QL/formatter.h"
|
||||
#include "QL/javascripter.h"
|
||||
#include "VocBase/index.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -98,12 +99,16 @@ QL_optimize_range_type_e;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Range value types
|
||||
///
|
||||
/// Currently supported types are doubles (numbers) and strings
|
||||
/// Currently supported types are collection attributes (fields), doubles
|
||||
/// (numbers), strings, and JSON documents.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef enum {
|
||||
RANGE_TYPE_DOUBLE = 0,
|
||||
RANGE_TYPE_STRING = 1
|
||||
RANGE_TYPE_FIELD = 1,
|
||||
RANGE_TYPE_DOUBLE = 2,
|
||||
RANGE_TYPE_STRING = 3,
|
||||
RANGE_TYPE_JSON = 4
|
||||
|
||||
}
|
||||
QL_optimize_range_value_type_e;
|
||||
|
||||
|
@ -146,6 +151,10 @@ typedef struct QL_optimize_range_s {
|
|||
double _doubleValue;
|
||||
char* _stringValue;
|
||||
} _maxValue;
|
||||
struct {
|
||||
char* _collection;
|
||||
char *_field;
|
||||
} _refValue;
|
||||
uint64_t _hash;
|
||||
QL_optimize_range_type_e _minStatus;
|
||||
QL_optimize_range_type_e _maxStatus;
|
||||
|
|
Loading…
Reference in New Issue