Android Room编译时警告外​​键中的列不是索引的一部分.这是什么意思?

mik*_*guy 31 sqlite android android-sqlite android-room

我正在使用最近在Google I/O上宣布的Android架构组件中的Android的Room Persistence Library.事情似乎有效,但我收到以下错误:

警告:tagId列引用外键但它不是索引的一部分.每当修改父表时,这可能会触发全表扫描,因此强烈建议您创建一个涵盖此列的索引.

我的数据库有3个表:Note,Tag,和JoinNotesTags.对标记的注释是多对多关系,因此JoinNotesTags表用于处理映射.表格很简单:

  • Note.id并且Tag.id都是主键
  • JoinNotesTags.noteId 引用 Note.id
  • JoinNotesTags.tagId 引用 Tag.id

外键约束在JoinNotesTags表上定义.作为参考,这是表的CREATE TABLE声明JoinNotesTags:

"CREATE TABLE IF NOT EXISTS `JoinNotesTags` (
    `id` INTEGER PRIMARY KEY AUTOINCREMENT, 
    `noteId` INTEGER, 
    `tagId` INTEGER, 
    FOREIGN KEY(`noteId`) REFERENCES `Note`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , 
    FOREIGN KEY(`tagId`) REFERENCES `Tag`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION 
)"
Run Code Online (Sandbox Code Playgroud)

这是@Entity该类的相应注释:

@Entity(
        indices = arrayOf(Index(value = *arrayOf("noteId", "tagId"), unique = true)),
        foreignKeys = arrayOf(
                ForeignKey(
                        entity = Note::class,
                        parentColumns = arrayOf("id"),
                        childColumns = arrayOf("noteId"),
                        onDelete = ForeignKey.CASCADE),
                ForeignKey(
                        entity = Tag::class,
                        parentColumns = arrayOf("id"),
                        childColumns = arrayOf("tagId"))
        )
)
Run Code Online (Sandbox Code Playgroud)

从@Entity注释中可以看出,tagId 它包含在复合唯一索引中noteId.我已经确认在自动生成的json模式文件中也正确定义了这个索引:

"CREATE UNIQUE INDEX `index_JoinNotesTags_noteId_tagId` 
    ON `JoinNotesTags` (`noteId`, `tagId`)"
Run Code Online (Sandbox Code Playgroud)

所以,我的问题:这个警告只是(仍然是alpha版本的)房间库中的一个错误 - 即编译时分析缺少tagId这个复合索引的一部分吗?或者我是否真的有一个索引问题,我需要解决,以避免全表扫描?

Pra*_*ash 38

您需要为列添加索引以便更快地进行查询以下是一个示例

@Entity(indices = {@Index("artist_id")})
public class Artist{
    @NonNull
    @PrimaryKey
    @ColumnInfo(name = "artist_id")
    public String id;
    public String name;
}
Run Code Online (Sandbox Code Playgroud)


小智 27

当使用kotlin代码时:

之前

@Expose
@SerializedName("question_id")
@ColumnInfo(name = "question_id")
var questionId: Long
Run Code Online (Sandbox Code Playgroud)

后

@Expose
    @SerializedName("question_id")
    @ColumnInfo(name = "question_id", index = true) //just add index = true
    var questionId: Long
Run Code Online (Sandbox Code Playgroud)

  • 这对我有用。为了便于阅读,只需使用“@ColumnInfo”行的前后即可简化答案。其余的,尤其是 Retrofit 的“@Expose”和“@SerializedName”,是不相关的,并且在大多数情况下不会在数据库实体中使用。 (3认同)

CL.*_*CL. 15

修改Tag表时,数据库可能需要查找JoinNotesTags表中的相应行.为了提高效率,这需要tagId列上的索引.

您的复合索引对此无用; 由于索引的工作方式,要搜索的列必须是索引中最左边的列.

您应该只在tagId列上添加索引.(你可以交换复合索引中列的顺序,但是你会遇到同样的问题noteId.)

  • 你能添加样本插图吗? (35认同)
  • 引用你的话:`你应该只在 tagId 列上添加索引`。这是否意味着 noteId 和 tagId 应该是单独的索引。? (2认同)
  • @AshishKrishnan是的,两者都应该是索引中最左边的列。 (2认同)