diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
index dcc4aedaea2f05d6dad0b038d47773988071e6cb..c11365dfdea620da9b68192954174876595506df 100644
--- a/src/box/tuple_compare.cc
+++ b/src/box/tuple_compare.cc
@@ -829,54 +829,67 @@ tuple_compare_with_key_slowpath(struct tuple *tuple, hint_t tuple_hint,
 	return 0;
 }
 
+/**
+ * Compare key parts and skip compared equally. After function call, keys
+ * will point to the first field that differ or to the end of key or
+ * part_count + 1 field in order.
+ * Key arguments must not be NULL, allowed to be NULL if dereferenced.
+ */
 template<bool is_nullable>
 static inline int
-key_compare_parts(const char *key_a, const char *key_b, uint32_t part_count,
-		  struct key_def *key_def)
+key_compare_and_skip_parts(const char **key_a, const char **key_b,
+			   uint32_t part_count, struct key_def *key_def)
 {
 	assert(is_nullable == key_def->is_nullable);
-	assert((key_a != NULL && key_b != NULL) || part_count == 0);
+	assert(key_a != NULL && key_b != NULL);
+	assert((*key_a != NULL && *key_b != NULL) || part_count == 0);
 	struct key_part *part = key_def->parts;
+	int rc;
 	if (likely(part_count == 1)) {
+		enum mp_type a_type = mp_typeof(**key_a);
+		enum mp_type b_type = mp_typeof(**key_b);
 		if (! is_nullable) {
-			return tuple_compare_field(key_a, key_b, part->type,
-						   part->coll);
-		}
-		enum mp_type a_type = mp_typeof(*key_a);
-		enum mp_type b_type = mp_typeof(*key_b);
-		if (a_type == MP_NIL) {
-			return b_type == MP_NIL ? 0 : -1;
+			rc = tuple_compare_field(*key_a, *key_b, part->type,
+						 part->coll);
+		} else if (a_type == MP_NIL) {
+			rc = b_type == MP_NIL ? 0 : -1;
 		} else if (b_type == MP_NIL) {
-			return 1;
+			rc = 1;
 		} else {
-			return tuple_compare_field_with_type(key_a, a_type,
-							     key_b, b_type,
-							     part->type,
-							     part->coll);
+			rc = tuple_compare_field_with_type(*key_a, a_type,
+							   *key_b, b_type,
+							   part->type,
+							   part->coll);
 		}
+		/* If key parts are equals, we must skip them. */
+		if (rc == 0) {
+			mp_next(key_a);
+			mp_next(key_b);
+		}
+		return rc;
 	}
 
 	struct key_part *end = part + part_count;
-	int rc;
-	for (; part < end; ++part, mp_next(&key_a), mp_next(&key_b)) {
+	for (; part < end; ++part, mp_next(key_a), mp_next(key_b)) {
 		if (! is_nullable) {
-			rc = tuple_compare_field(key_a, key_b, part->type,
+			rc = tuple_compare_field(*key_a, *key_b, part->type,
 						 part->coll);
 			if (rc != 0)
 				return rc;
 			else
 				continue;
 		}
-		enum mp_type a_type = mp_typeof(*key_a);
-		enum mp_type b_type = mp_typeof(*key_b);
+		enum mp_type a_type = mp_typeof(**key_a);
+		enum mp_type b_type = mp_typeof(**key_b);
 		if (a_type == MP_NIL) {
 			if (b_type != MP_NIL)
 				return -1;
 		} else if (b_type == MP_NIL) {
 			return 1;
 		} else {
-			rc = tuple_compare_field_with_type(key_a, a_type, key_b,
-							   b_type, part->type,
+			rc = tuple_compare_field_with_type(*key_a, a_type,
+							   *key_b, b_type,
+							   part->type,
 							   part->coll);
 			if (rc != 0)
 				return rc;
@@ -885,6 +898,15 @@ key_compare_parts(const char *key_a, const char *key_b, uint32_t part_count,
 	return 0;
 }
 
+template<bool is_nullable>
+static inline int
+key_compare_parts(const char *key_a, const char *key_b, uint32_t part_count,
+		  struct key_def *key_def)
+{
+	return key_compare_and_skip_parts<is_nullable>(&key_a, &key_b,
+						       part_count, key_def);
+}
+
 template<bool is_nullable, bool has_optional_parts>
 static inline int
 tuple_compare_with_key_sequential(struct tuple *tuple, hint_t tuple_hint,