diff --git a/src/box/tuple.cc b/src/box/tuple.cc
index 0ab3a3c98d0631f19aa4a030594c9df824689caa..e81dc4cd6d9b6b33346f8351fa2563be0e035323 100644
--- a/src/box/tuple.cc
+++ b/src/box/tuple.cc
@@ -37,6 +37,7 @@
 #include <palloc.h>
 #include <fiber.h>
 #include "scoped_guard.h"
+#include <stdio.h>
 
 /** Global table of tuple formats */
 struct tuple_format **tuple_formats;
@@ -141,7 +142,7 @@ tuple_ref(struct tuple *tuple, int count)
  * @returns field data if field exists or NULL
  */
 const char *
-tuple_field_old(struct tuple *tuple, uint32_t i)
+tuple_field_old(const struct tuple *tuple, uint32_t i)
 {
 	const char *field = tuple->data;
 	const char *tuple_end = tuple->data + tuple->bsize;
@@ -292,77 +293,55 @@ tuple_new(struct tuple_format *format, uint32_t field_count,
 	return new_tuple;
 }
 
+/*
+ * Compare two tuple fields.
+ * Separate version exists since compare is a very
+ * often used operation, so any performance speed up
+ * in it can have dramatic impact on the overall
+ * server performance.
+ */
 static inline int
-tuple_compare_field(const char *field_a, uint32_t size_a,
-		    const char *field_b, uint32_t size_b,
+tuple_compare_field(const char *field_a, const char *field_b,
 		    enum field_type type)
 {
-	/*
-	 * field_a is always a tuple field.
-	 * field_b can be either a tuple field or a key part.
-	 * All tuple fields were validated before by space_validate_tuple().
-	 * All key parts were validated before by key_validate().
-	 */
-	switch (type) {
-	case NUM:
-	{
-		assert(size_a == sizeof(uint32_t));
-		assert(size_b == sizeof(uint32_t));
-		uint32_t a = *(uint32_t *) field_a;
-		uint32_t b = *(uint32_t *) field_b;
-		return a < b ? -1 : (a > b);
-	}
-	case NUM64:
-	{
-		assert(size_a == sizeof(uint64_t));
-		uint64_t a = *(uint64_t *) field_a;
-		uint64_t b;
-		/* Allow search in NUM64 indexes using NUM keys. */
-		if (size_b == sizeof(uint32_t)) {
-			b = *(uint32_t *) field_b;
-		} else {
-			assert(size_b == sizeof(uint64_t));
-			b = *(uint64_t *) field_b;
-		}
-		return a < b ? -1 : (a > b);
-	}
-	case STRING:
-	{
-		int cmp = memcmp(field_a, field_b, MIN(size_a, size_b));
-		if (cmp != 0)
-			return cmp;
-
-		if (size_a > size_b) {
-			return 1;
-		} else if (size_a < size_b){
-			return -1;
-		} else {
-			return 0;
-		}
-	}
-	default:
-		assert(false);
+	if (type != STRING) {
+		printf("len: %d\n", field_a[0]);
+		assert(field_a[0] == field_b[0]);
+		/*
+		 * Little-endian unsigned int is memcmp
+		 * compatible.
+		 */
+		return memcmp(field_a + 1, field_b + 1, field_a[0]);
 	}
+	uint32_t size_a = load_varint32(&field_a);
+	uint32_t size_b = load_varint32(&field_b);
+	int r = memcmp(field_a, field_b, MIN(size_a, size_b));
+	if (r == 0)
+		r = size_a < size_b ? -1 : size_a > size_b;
+	return r;
 }
 
 int
 tuple_compare(const struct tuple *tuple_a, const struct tuple *tuple_b,
 	      const struct key_def *key_def)
 {
-	for (uint32_t part = 0; part < key_def->part_count; part++) {
-		uint32_t field_no = key_def->parts[part].fieldno;
-		uint32_t size_a, size_b;
-		const char *field_a = tuple_field(tuple_a, field_no, &size_a);
-		const char *field_b = tuple_field(tuple_b, field_no, &size_b);
-
-		int r = tuple_compare_field(field_a, size_a, field_b, size_b,
-					    key_def->parts[part].type);
-		if (r != 0) {
-			return r;
-		}
+	if (key_def->part_count == 1 && key_def->parts[0].fieldno == 0)
+		return tuple_compare_field(tuple_a->data, tuple_b->data,
+					   key_def->parts[0].type);
+
+	struct key_part *part = key_def->parts;
+	struct key_part *end = part + key_def->part_count;
+	const char *field_a;
+	const char *field_b;
+	int r;
+
+	for (; part < end; part++) {
+		field_a = tuple_field_old(tuple_a, part->fieldno);
+		field_b = tuple_field_old(tuple_b, part->fieldno);
+		if ((r = tuple_compare_field(field_a, field_b, part->type)))
+			break;
 	}
-
-	return 0;
+	return r;
 }
 
 int
@@ -370,36 +349,52 @@ tuple_compare_dup(const struct tuple *tuple_a, const struct tuple *tuple_b,
 		  const struct key_def *key_def)
 {
 	int r = tuple_compare(tuple_a, tuple_b, key_def);
-	if (r != 0) {
-		return r;
-	}
+	if (r == 0)
+		r = tuple_a < tuple_b ? -1 : tuple_a > tuple_b;
 
-	return tuple_a < tuple_b ? -1 : (tuple_a > tuple_b);
+	return r;
 }
 
 int
-tuple_compare_with_key(const struct tuple *tuple_a, const char *key,
+tuple_compare_with_key(const struct tuple *tuple, const char *key,
 		       uint32_t part_count, const struct key_def *key_def)
 {
-	part_count = MIN(part_count, key_def->part_count);
-	for (uint32_t part = 0; part < part_count; part++) {
-		uint32_t field_no = key_def->parts[part].fieldno;
-
-		uint32_t size_a;
-		const char *field_a = tuple_field(tuple_a, field_no,
-						  &size_a);
-
-		uint32_t key_size = load_varint32(&key);
-		int r = tuple_compare_field(field_a, size_a, key, key_size,
-					    key_def->parts[part].type);
-		if (r != 0) {
-			return r;
+	struct key_part *part = key_def->parts;
+	struct key_part *end = part + MIN(part_count, key_def->part_count);
+	const char *field;
+	uint32_t field_size;
+	uint32_t key_size;
+	int r = 0; /* Part count can be 0 in wildcard searches. */
+	for (; part < end; part++, key += key_size) {
+		field = tuple_field_old(tuple, part->fieldno);
+		field_size = load_varint32(&field);
+		key_size = load_varint32(&key);
+		switch (part->type) {
+		case NUM:
+			r = memcmp(field, key, sizeof(uint32_t));
+			break;
+		case NUM64:
+			if (key_size == sizeof(uint32_t)) {
+				/*
+				 * Allow search in NUM64 indexes
+				 * using NUM keys.
+				 */
+				uint64_t b = *(uint32_t *) key;
+				r = memcmp(field, &b, sizeof(uint64_t));
+			} else {
+				r = memcmp(field, key, sizeof(uint64_t));
+			}
+			break;
+		default:
+			r = memcmp(field, key, MIN(field_size, key_size));
+			if (r == 0)
+				r = field_size < key_size ? -1 : field_size > key_size;
+			break;
 		}
-
-		key += key_size;
+		if (r != 0)
+			break;
 	}
-
-	return 0;
+	return r;
 }
 
 void
diff --git a/src/box/tuple.h b/src/box/tuple.h
index f43782b899b71a204981a5bea36f93650ae81201..2c2a949f3e31848fdfeb71c1be1fc77f81787fbb 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -141,7 +141,7 @@ tuple_format(const struct tuple *tuple)
  * @returns field data if the field exists, or NULL
  */
 const char *
-tuple_field_old(struct tuple *tuple, uint32_t i);
+tuple_field_old(const struct tuple *tuple, uint32_t i);
 
 /**
  * @brief Return field data of the field