diff --git a/src/box/tuple.cc b/src/box/tuple.cc
index e81dc4cd6d9b6b33346f8351fa2563be0e035323..7df09643e9139b91067a17af5f0312348e5ef00d 100644
--- a/src/box/tuple.cc
+++ b/src/box/tuple.cc
@@ -84,10 +84,28 @@ tuple_format_alloc_and_register(uint32_t offset_count)
 struct tuple_format *
 tuple_format_new(const enum field_type *fields, uint32_t max_fieldno)
 {
-	(void) max_fieldno;
-	(void) fields;
 	struct tuple_format *format =
-		tuple_format_alloc_and_register(0);
+		tuple_format_alloc_and_register(max_fieldno);
+
+	uint32_t i = 0;
+	uint32_t prev_offset = 0;
+
+	/*
+	 * In the format, store all offsets available,
+	 * they may be useful.
+	 */
+	for (; i < max_fieldno; i++) {
+		uint32_t maxlen = field_type_maxlen(fields[i]);
+		if (maxlen == UINT32_MAX)
+			break;
+		format->offset[i] = (varint32_sizeof(maxlen) + maxlen +
+				     prev_offset);
+		assert(format->offset[i] > 0);
+		prev_offset = format->offset[i];
+	}
+	for (; i < max_fieldno; i++)
+		format->offset[i] = INT32_MIN;
+
 
 	return format;
 }
@@ -142,25 +160,34 @@ tuple_ref(struct tuple *tuple, int count)
  * @returns field data if field exists or NULL
  */
 const char *
-tuple_field_old(const struct tuple *tuple, uint32_t i)
+tuple_field_old(const struct tuple_format *format,
+		const struct tuple *tuple, uint32_t i)
 {
 	const char *field = tuple->data;
-	const char *tuple_end = tuple->data + tuple->bsize;
+
+	if (i == 0)
+		return field;
+	i--;
+	if (i < format->offset_count) {
+		if (format->offset[i] > 0)
+			return field + format->offset[i];
+	}
+	const char *tuple_end = field + tuple->bsize;
 
 	while (field < tuple_end) {
-		if (i == 0)
-			return field;
 		uint32_t len = load_varint32(&field);
 		field += len;
+		if (i == 0)
+			return field;
 		i--;
 	}
 	return tuple_end;
 }
 
 const char *
-tuple_field(const struct tuple *tuple, uint32_t field_no, uint32_t *len)
+tuple_field(const struct tuple *tuple, uint32_t i, uint32_t *len)
 {
-	const char *field = tuple_field_old((struct tuple *) tuple, field_no);
+	const char *field = tuple_field_old(tuple_format(tuple), tuple, i);
 	if (field < tuple->data + tuple->bsize) {
 		*len = load_varint32(&field);
 		return field;
@@ -169,9 +196,9 @@ tuple_field(const struct tuple *tuple, uint32_t field_no, uint32_t *len)
 }
 
 const char *
-tuple_seek(struct tuple_iterator *it, uint32_t field_no, uint32_t *len)
+tuple_seek(struct tuple_iterator *it, uint32_t i, uint32_t *len)
 {
-	it->pos = tuple_field_old((struct tuple *) it->tuple, field_no);
+	it->pos = tuple_field_old(tuple_format(it->tuple), it->tuple, i);
 	return tuple_next(it, len);
 }
 
@@ -331,13 +358,15 @@ tuple_compare(const struct tuple *tuple_a, const struct tuple *tuple_b,
 
 	struct key_part *part = key_def->parts;
 	struct key_part *end = part + key_def->part_count;
+	struct tuple_format *format_a = tuple_format(tuple_a);
+	struct tuple_format *format_b = tuple_format(tuple_b);
 	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);
+		field_a = tuple_field_old(format_a, tuple_a, part->fieldno);
+		field_b = tuple_field_old(format_b, tuple_b, part->fieldno);
 		if ((r = tuple_compare_field(field_a, field_b, part->type)))
 			break;
 	}
@@ -361,12 +390,13 @@ tuple_compare_with_key(const struct tuple *tuple, const char *key,
 {
 	struct key_part *part = key_def->parts;
 	struct key_part *end = part + MIN(part_count, key_def->part_count);
+	struct tuple_format *format = tuple_format(tuple);
 	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 = tuple_field_old(format, tuple, part->fieldno);
 		field_size = load_varint32(&field);
 		key_size = load_varint32(&key);
 		switch (part->type) {
diff --git a/src/box/tuple.h b/src/box/tuple.h
index 2c2a949f3e31848fdfeb71c1be1fc77f81787fbb..61b9d40976a638f0491c6dc46b20d9944b6e9cb0 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -45,6 +45,21 @@ struct tuple_format {
 	 * first field).
 	 */
 	uint32_t offset_count;
+	/**
+	 * For each field participating in an index, the format
+	 * may either store the fixed offset of the field
+	 * (identical in all tuples with this format), or an
+	 * offset in the dynamic offset map (field_map), which,
+	 * in turn, stores the offset of the field (such offset is
+	 * varying between different tuples of the same format).
+	 * If an offset is fixed, it's positive, so that
+	 * tuple->data[format->offset[fieldno] gives the
+	 * start of the field.
+	 * If it is varying, it's negative, so that
+	 * tuple->data[((uint32_t *) * tuple)[format->offset[fieldno]]]
+	 * gives the start of the field.
+	 */
+	int32_t offset[0];
 };
 
 extern struct tuple_format **tuple_formats;
@@ -137,11 +152,12 @@ tuple_format(const struct tuple *tuple)
 
 /**
  * Get a field from tuple by index.
+ * Returns a pointer to BER-length prefixed field.
  *
- * @returns field data if the field exists, or NULL
  */
 const char *
-tuple_field_old(const struct tuple *tuple, uint32_t i);
+tuple_field_old(const struct tuple_format *format,
+		const struct tuple *tuple, uint32_t i);
 
 /**
  * @brief Return field data of the field