Android房间@关系和索引

Android房间@关系和索引,android,android-room,Android,Android Room,我在我的房间设置中有这个类,它将我的状态表中的数据与我的国家表中的相应数据组合在一起: public class StateWithCountryData { @Embedded public State state; @Relation(parentColumn = "country_id", entityColumn = "_id", entity = Country.class) public Country country; } 正如您在my@Rel

我在我的房间设置中有这个类,它将我的
状态
表中的数据与我的
国家
表中的相应数据组合在一起:

public class StateWithCountryData {

    @Embedded
    public State state;

    @Relation(parentColumn = "country_id", entityColumn = "_id", entity = Country.class)
    public Country country;
}
正如您在my@Relationship代码中所看到的,my
states
country\u id
列与my
countries
列合并

我想知道的是@relationcode是否会在
states
country\u id
上创建一个自动索引,还是我需要自己在State实体类中创建索引

如果是后者,我如何将所需的添加到我的状态实体类中?这是:

@Entity(tableName = "states")
public class State {

    @PrimaryKey
    @ColumnInfo(name = "_id")
    private long stateId;

    @NonNull
    @ColumnInfo(name = "state_name")
    private String stateName;

    @ColumnInfo(name = "country_id")
    private long countryId;

    @ColumnInfo(name = "last_modified")
    private Date lastModified;

    public State(long stateId, @NonNull String stateName, long countryId, Date lastModified) {
        this.stateId = stateId;
        this.stateName = stateName;
        this.countryId = countryId;
        this.lastModified = lastModified;
    }

    public long getStateId() {
        return stateId;
    }

    public void setStateId(long stateId) {
        this.stateId = stateId;
    }

    @NonNull
    public String getStateName() {
        return stateName;
    }

    public void setStateName(@NonNull String stateName) {
        this.stateName = stateName;
    }

    public long getCountryId() {
        return countryId;
    }

    public void setCountryId(long countryId) {
        this.countryId = countryId;
    }

    public Date getLastModified() {
        return lastModified;
    }

    public void setLastModified(Date lastModified) {
        this.lastModified = lastModified;
    }
}
我想知道的是@relationcode是否会在states.country_id上创建一个自动索引,还是我需要自己在State实体类中创建索引

检查的方法是查看为@database生成的代码,例如,您会得到如下结果:-

final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(1) {
  @Override
  public void createAllTables(SupportSQLiteDatabase _db) {
    _db.execSQL("CREATE TABLE IF NOT EXISTS `Country` (`id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`id`))");
    _db.execSQL("CREATE TABLE IF NOT EXISTS `states` (`_id` INTEGER NOT NULL, `state_name` TEXT NOT NULL, `country_id` INTEGER NOT NULL, `last_modified` TEXT, PRIMARY KEY(`_id`))");
    _db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
    _db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '008d8fa1f719c970d7a1182e9e43f80b')");
  }
.....
如您所见,答案是否定的

如果是后者,我如何将所需的索引添加到我的状态实体类中

您可以使用:-

@Entity(tableName = "states"
    , indices = {@Index(name = "ixCountryId", value = "country_id")} //<<<<<<<<<< ADDED
    )
i、 e.线路

 _db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `ixCountryId` ON `states` (`country_id`)");
已添加

一个更简单的选项是在@ColumnInfo级别编码,而不是在@Entity级别编码标记,例如

@ColumnInfo(name = "country_id", index = true)
private long countryId;
在上述情况下,这将自动生成索引名和结果,生成的代码中包含以下内容(而不是前面显示的行):-

您也可以同时使用这两种方法(不是您会做的事情,因为这是一种浪费/低效),这将导致:-

    _db.execSQL("CREATE INDEX IF NOT EXISTS `ix01` ON `states` (`country_id`)");
    _db.execSQL("CREATE INDEX IF NOT EXISTS `index_states_country_id` ON `states` (`country_id`)");
  • @Entity级别的编码提供了更多选项,如复杂(多列)或唯一索引
或者我需要自己在State实体类中创建索引吗

不一定,也可能不是,因为该指数似乎有负面影响,尽管取决于国家和州的数量,如果相当低,则影响可能微不足道

考虑以下测试代码,该代码创建了10000个国家和500000个国家,随机分配给这些国家(每个国家大约50个国家)

使用两个核心查询:-

SELECT * FROM states WHERE country_id > 500;
SELECT * FROM states JOIN Country ON Country.id = states.country_id WHERE country_id < 500;
从国家id>500的州中选择*;
选择*FROM states JOIN Country.id=states.Country\u id,其中Country\u id<500;
在创建索引之前和之后,索引之前的计时是

SELECT * FROM states WHERE country_id > 500
> OK
> Time: 0.563s


SELECT * FROM states JOIN Country ON Country.id = states.country_id WHERE country_id < 500
> OK
> Time: 0.074s
从国家/地区id>500的州中选择*
>嗯
>时间:0.563s
选择*FROM states JOIN Country.id=states.Country\u id,其中Country\u id<500
>嗯
>时间:0.074s
在创建索引之后,有:-

SELECT * FROM states WHERE country_id > 500
> OK
> Time: 2.764s


SELECT * FROM states JOIN Country ON Country.id = states.country_id WHERE country_id < 500
> OK
> Time: 0.158s
从国家/地区id>500的州中选择*
>嗯
>时间:2.764s
选择*FROM states JOIN Country.id=states.Country\u id,其中Country\u id<500
>嗯
>时间:0.158s
因此索引速度较慢(第一次查询大约慢5倍,第二次查询慢9.5倍)


在运行查询之前,代码还会执行解释查询计划

创建索引之前:-

问题1:-

问题2:-

创建索引后

问题1:-

问题2:-

使用的代码(使用Navicat):-

DROP TABLE IF EXISTS Country;
DROP TABLE IF EXISTS states;
CREATE TABLE IF NOT EXISTS `Country` (`id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`id`));
CREATE TABLE IF NOT EXISTS `states` (`_id` INTEGER NOT NULL, `state_name` TEXT NOT NULL, `country_id` INTEGER NOT NULL, `last_modified` TEXT, PRIMARY KEY(`_id`));

/* Load data into the Country table */
WITH RECURSIVE cte1(counter,base) AS (
    SELECT 1, 'COUNTRY_A'
    UNION ALL SELECT counter+1,'COUNTRY_A' FROM cte1 LIMIT 10000
)
INSERT INTO Country (name) SELECT base||counter FROM cte1; 

/* Load fata into the states table */
WITH RECURSIVE cte1(counter,base,cid) AS (
  SELECT 1,'STATE_S', (abs(random()) % (SELECT count() FROM Country)) + 1
    UNION ALL SELECT 
        counter+1,
        'STATE_S',
      (abs(random()) % (SELECT count() FROM Country)) + 1   
    FROM cte1 LIMIT 500000
)
INSERT INTO states (state_name, country_id) SELECT base||counter, cid FROM cte1; 

EXPLAIN QUERY PLAN
SELECT * FROM states JOIN Country ON Country.id = states.country_id WHERE country_id < 500;
EXPLAIN QUERY PLAN
SELECT * FROM states WHERE country_id > 500;

SELECT * FROM states WHERE country_id > 500;
SELECT * FROM states JOIN Country ON Country.id = states.country_id WHERE country_id < 500;

/* Create the Index */
CREATE INDEX IF NOT EXISTS `ix01` ON `states` (`country_id`);

EXPLAIN QUERY PLAN
SELECT * FROM states JOIN Country ON Country.id = states.country_id WHERE country_id < 500;
EXPLAIN QUERY PLAN
SELECT * FROM states WHERE country_id > 500;

SELECT * FROM states WHERE country_id > 500;
SELECT * FROM states JOIN Country ON Country.id = states.country_id WHERE country_id < 500;

/* Show states per country */
SELECT Country.name,count() AS states_inCountry FROM States JOIN Country ON country_id = Country.id GROUP BY country_id;

/* Clean up */
DROP INDEX IF EXISTS ix01;
DROP TABLE IF EXISTS states;
DROP TABLE If EXISTS Country;
删除表格(如果国家/地区存在);
如果存在状态,则删除表;
如果不存在“Country”(`id`整数不为NULL,`name`文本,主键(`id`)),则创建表;
如果不存在“states”(“state”id“INTEGER NOT NULL”,“state”name“TEXT NOT NULL”,“country”id“INTEGER NOT NULL”,“last_modified”TEXT,主键(“'u id')),则创建表;
/*将数据加载到国家/地区表中*/
递归cte1(计数器,基)为(
选择1,“国家/地区”
联合所有选择计数器+1,cte1限制10000中的“国家/地区”
)
插入国家/地区(名称),从cte1中选择基本| |计数器;
/*将fata加载到状态表中*/
递归cte1(计数器、基、cid)为(
选择1,'STATE_S',(abs(random())%(SELECT count()FROM Country))+1
联合所有选择
计数器+1,
“州”,
(abs(random())%(从国家/地区选择count())+1
从cte1限额500000起
)
插入州(州名称、国家id)选择基本计数器、cte1中的cid;
解释查询计划
选择*FROM states JOIN Country.id=states.Country\u id,其中Country\u id<500;
解释查询计划
从国家/地区id>500的州中选择*;
从国家/地区id>500的州中选择*;
选择*FROM states JOIN Country.id=states.Country\u id,其中Country\u id<500;
/*创建索引*/
如果“州”(“国家/地区id”)上不存在“ix01”,则创建索引;
解释查询计划
选择*FROM states JOIN Country.id=states.Country\u id,其中Country\u id<500;
解释查询计划
从国家/地区id>500的州中选择*;
从国家/地区id>500的州中选择*;
选择*FROM states JOIN Country.id=states.Country\u id,其中Country\u id<500;
/*显示每个国家的州*/
选择Country.name,count(),因为counters\u incontry从states加入Country\u id=Country.id按Country\u id分组;
/*清理*/
如果存在ix01,则删除索引;
如果存在状态,则删除表;
如果国家/地区存在,则删除表格;
  • 注意,这可能有点不公平的比较/测试,因为索引创建可能会对后续运行条件产生影响。理想情况下,查询应该彼此分开运行,并且与索引创建分开
我想知道的是@relationcode是否会在states.country_id上创建一个自动索引,还是我需要自己在State实体类中创建索引

检查的方法是查看为@database生成的代码,例如,您会得到如下结果:-

final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(1) {
  @Override
  public void createAllTables(SupportSQLiteDatabase _db) {
    _db.execSQL("CREATE TABLE IF NOT EXISTS `Country` (`id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`id`))");
    _db.execSQL("CREATE TABLE IF NOT EXISTS `states` (`_id` INTEGER NOT NULL, `state_name` TEXT NOT NULL, `country_id` INTEGER NOT NULL, `last_modified` TEXT, PRIMARY KEY(`_id`))");
    _db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
    _db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '008d8fa1f719c970d7a1182e9e43f80b')");
  }
.....
如您所见,答案是否定的

如果是后者,我如何将所需的索引添加到我的状态实体类中

您可以使用:-

@Entity(tableName = "states"
    , indices = {@Index(name = "ixCountryId", value = "country_id")} //<<<<<<<<<< ADDED
    )
i、 e.线路

 _db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `ixCountryId` ON `states` (`country_id`)");
已添加

一个更简单的选择是使用c