Sorry for quite late respond, I sincerely regret it. Patch LGTM (except for several minor nits). > diff --git a/src/box/sql.c b/src/box/sql.c > index b158c50..87f2088 100644 > --- a/src/box/sql.c > +++ b/src/box/sql.c > @@ -1217,21 +1217,21 @@ void tarantoolSqlite3LoadSchema(struct init_data *init) > sql_init_callback(init, TARANTOOL_SYS_SQL_STAT1_NAME, > BOX_SQL_STAT1_ID, 0, > "CREATE TABLE \""TARANTOOL_SYS_SQL_STAT1_NAME > - "\"(\"tbl\" text," > - "\"idx\" text," > + "\"(\"space_id\" INT," > + "\"index_id\" INT," > "\"stat\" not null," > - "PRIMARY KEY(\"tbl\", \"idx\"))"); > + "PRIMARY KEY(\"space_id\", \"index_id\"))"); > > sql_init_callback(init, TARANTOOL_SYS_SQL_STAT4_NAME, > BOX_SQL_STAT4_ID, 0, > "CREATE TABLE \""TARANTOOL_SYS_SQL_STAT4_NAME > - "\"(\"tbl\" text," > - "\"idx\" text," > + "\"(\"space_id\" INT," > + "\"index_id\" INT," > "\"neq\" text," > "\"nlt\" text," > "\"ndlt\" text," > "\"sample\"," > - "PRIMARY KEY(\"tbl\", \"idx\", \"sample\"))"); > + "PRIMARY KEY(\"space_id\", \"index_id\", \"sample\"))”); Note: after you rebase on fresh 2.0, these fixes will disappear, since we don’t add system spaces to separate hash anymore. > diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c > index 76ae153..6938dcb 100644 > --- a/src/box/sql/analyze.c > +++ b/src/box/sql/analyze.c > @@ -38,8 +38,8 @@ > * > * The following system tables are or have been supported: > * > - * CREATE TABLE _sql_stat1(tbl, idx, stat); > - * CREATE TABLE _sql_stat4(tbl, idx, nEq, nLt, nDLt, sample); > + * CREATE TABLE _sql_stat1(space_id, index_id, stat); > + * CREATE TABLE _sql_stat4(space_id, index_id, nEq, nLt, nDLt, sample); > * > * For most applications, _sql_stat1 provides all the statistics required > * for the query planner to make good choices. > @@ -47,7 +47,7 @@ > * Format of _sql_stat1: > * > * There is normally one row per index, with the index identified by the > - * name in the idx column. The tbl column is the name of the table to > + * name in the index_id column. The space_id column is the name of the table to Nit: * id in the index_id column. The space_id column is the id of the space to > @@ -1410,27 +1405,14 @@ load_stat_from_space(struct sqlite3 *db, const char *sql_select_prepare, > goto finalize; > uint32_t current_idx_count = 0; > while (sqlite3_step(stmt) == SQLITE_ROW) { > - const char *space_name = (char *)sqlite3_column_text(stmt, 0); > - if (space_name == NULL) > - continue; > - const char *index_name = (char *)sqlite3_column_text(stmt, 1); > - if (index_name == NULL) > - continue; > - uint32_t sample_count = sqlite3_column_int(stmt, 2); > - uint32_t space_id = box_space_id_by_name(space_name, > - strlen(space_name)); > - assert(space_id != BOX_ID_NIL); > + uint32_t space_id = sqlite3_column_int(stmt, 0); > + assert(space_id != BOX_ID_NIL && space_id != 0); Above you have mentioned that space_id now can’t be equal to BOX_ID_NIL: >>> @@ -1246,24 +1246,14 @@ analysis_loader(void *data, int argc, char **argv, char **unused) >>> struct analysis_index_info *info = (struct analysis_index_info *) data; >>> assert(info->stats != NULL); >>> struct index_stat *stat = &info->stats[info->index_count++]; >>> - uint32_t space_id = box_space_id_by_name(argv[0], strlen(argv[0])); >>> + uint32_t space_id = atoll(argv[0]); >> I would add assertion like: >> assert(space_id != 0); >> Since atoll in case of fail returns 0 and BOX_ID_NIL != 0. > Actually now we cannot get BOX_ID_NIL, but we can get 0. Changed "if" > that placed next line after "atoll”. So, why do you check within assertion that condition? I mean there is no crime, but does it make sense? The same for other similar checks. > --- a/test/sql/sql-statN-index-drop.test.lua > +++ b/test/sql/sql-statN-index-drop.test.lua > @@ -14,15 +14,15 @@ box.sql.execute("INSERT INTO t2 VALUES(1, 2);") > box.sql.execute("ANALYZE;") > > -- Checking the data. > -box.sql.execute("SELECT * FROM \"_sql_stat4\";") > -box.sql.execute("SELECT * FROM \"_sql_stat1\";") > +box.sql.execute('SELECT "name","index_id","neq","nlt","ndlt","sample" FROM "_sql_stat4" join "_space" on "_sql_stat4"."space_id" = "_space"."id";') > +box.sql.execute('SELECT "name","index_id","stat" FROM "_sql_stat1" join "_space" on "_sql_stat1"."space_id" = "_space"."id";’) Nit: I don’t think that in this test (and the rest below) we need to fetch name of space instead of its id. Lets leave this test as it was before. > > -- Dropping an index. > box.sql.execute("DROP INDEX i1 ON t1;") > > -- Checking the DROP INDEX results. > -box.sql.execute("SELECT * FROM \"_sql_stat4\";") > -box.sql.execute("SELECT * FROM \"_sql_stat1\";") > +box.sql.execute('SELECT "name","index_id","neq","nlt","ndlt","sample" FROM "_sql_stat4" join "_space" on "_sql_stat4"."space_id" = "_space"."id";') > +box.sql.execute('SELECT "name","index_id","stat" FROM "_sql_stat1" join "_space" on "_sql_stat1"."space_id" = "_space"."id";') > > --Cleaning up. > box.sql.execute("DROP TABLE t1;") > @@ -41,15 +41,15 @@ box.sql.execute("INSERT INTO t2 VALUES(1, 2);") > box.sql.execute("ANALYZE;") > > -- Checking the data. > -box.sql.execute("SELECT * FROM \"_sql_stat4\";") > -box.sql.execute("SELECT * FROM \"_sql_stat1\";") > +box.sql.execute('SELECT "name","index_id","neq","nlt","ndlt","sample" FROM "_sql_stat4" join "_space" on "_sql_stat4"."space_id" = "_space"."id";') > +box.sql.execute('SELECT "name","index_id","stat" FROM "_sql_stat1" join "_space" on "_sql_stat1"."space_id" = "_space"."id";') > > -- Dropping an index. > box.sql.execute("DROP INDEX i1 ON t2;") > > -- Checking the DROP INDEX results. > -box.sql.execute("SELECT * FROM \"_sql_stat4\";") > -box.sql.execute("SELECT * FROM \"_sql_stat1\";") > +box.sql.execute('SELECT "name","index_id","neq","nlt","ndlt","sample" FROM "_sql_stat4" join "_space" on "_sql_stat4"."space_id" = "_space"."id";') > +box.sql.execute('SELECT "name","index_id","stat" FROM "_sql_stat1" join "_space" on "_sql_stat1"."space_id" = "_space"."id";') >