我有一个桌子参与者连接桌子,锦标赛和球员.为此,我写道:

@Entity(tableName = "participants", foreignKeys = [
ForeignKey(entity = TournamentEntity::class,
    parentColumns = ["id"],
    childColumns = ["tournamentId"],
    onDelete = ForeignKey.CASCADE),
ForeignKey(entity = PlayerEntity::class,
    parentColumns = ["id"],
    childColumns = ["playerId"],
    onDelete = ForeignKey.CASCADE),
], primaryKeys = ["tournamentId","playerId"])
data class ParticipantEntity(
var tournamentId:Long,
var playerId:Long
)

但在构建过程中,我看到了警告:

playerId column references a foreign key but it is not part of an index. This may trigger full table scans whenever parent table is modified so you are highly advised to create an index that covers this column.

通常,当外键是主键的一部分时,没有必要创建索引.

请问,要解决这个问题需要遵循什么程序?

推荐答案

警告是因为PlayerID不是构造索引(PrimaryKey)的主要依据.也就是说,索引、主键将首先使用TournamentId构建,然后使用PlayerId构建.

  • 也就是说,这只是一个警告,而且"不是索引的一部分"也不是对问题的准确描述.

因此,基于PlayerId的表搜索必须扫描rowid或主键才能找到有问题的PlayerId.

  • as Room with few exceptions requires the use of a rowid table, there is always an index on the normally hidden rowid column. This can be up to twice as fast to scan than other indexes, so may be the index used as decided by the query optimiser.

要删除警告,只需使用:-

@ColumnInfo(index = true)
var playerId:Long

然后,PlayerId上的指数将存在并得到维护.如果是,则可以通过索引获得playerID的相应行.

  • 请注意,在插入/删除和可能更新时维护附加索引会产生开销,但在查询时会有潜在的yield .

Demonstration (using SQLite tool)

请考虑以下事项:

DROP TABLE IF EXISTS pe;
CREATE TABLE IF NOT EXISTS pe (t TEXT, p TEXT, PRIMARY KEY(t,p));
/* add some data generated recursively (no need to understand just that 250000 rows are added)*/
WITH
    cte_counter(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM cte_counter LIMIT 500),
    cte_t(t_name) AS (SELECT 'TRN'||n FROM cte_counter),
    cte_p(p_name) AS (SELECT 'PLY'||n FROM cte_counter)
INSERT INTO pe SELECT t_name,p_name FROM cte_t JOIN cte_p;

/* Demonstrate access WITHOUT an index on the p column */
EXPLAIN QUERY PLAN
SELECT * FROM pe WHERE p='PLY1';
SELECT * FROM pe WHERE p= 'PLY1';
/* Add the index on the p column aka @ColumnInfo(index = true) */
CREATE INDEX pe_idxon_p_column ON pe(p);
/* Demonstrate access WITHOUT an index on the p column */
EXPLAIN QUERY PLAN
SELECT * FROM pe WHERE p='PLY1';
SELECT * FROM pe WHERE p='PLY1';
/* Cleanup demo environment */
DROP TABLE IF EXISTS pe;

这是:-

  1. creates some 250000 rows with every combination of t (TRN1 - TRN500) and p (pLY1 - PLY500).
    1. 不需要理解如何
    2. 消息> Affected rows: 250000> Time: 0.833s
  2. Asks for an explanation of what the the query SELECT * FROM pe WHERE p='PLY1'个 does.
    1. Output is enter image description here i.e. A FULL scan of the table
  3. 运行查询,重要的是日志(log)中的消息是:-
    1. SELECT * FROM pe WHERE p= 'PLY1'
    2. > OK个个
    3. 102
  4. p列上创建索引.
  5. Explains the same query BUT NOW:-
    1. Output is enter image description here i.e the pe_indexon_p_column will be used.
  6. Runs the EXACT same query, now the messages to the log are:-
    1. SELECT * FROM pe WHERE p='PLY1'
    2. > OK个个
    3. 100

0.012 seconds is noticeably less than the FULL SCAN that took 0.032 seconds

Kotlin相关问答推荐

UByte范围. Min_UTE.. UByte.MAX_UTE不符合预期

如何在使用Kotlin Coroutines时检测和记录何时出现背压

在Kotlin中求n个ClosedRange实例相交的最常用方法是什么?

处理合成层次 struct 中的深层按钮以切换视图

Kotlin 中命名构造函数的惯用方式

如何将消费者放入 Kotlin 的 map 中?

Kotlin 中的 maxOf() 和 max() 方法有什么区别?

为什么 Kotlin 中的 Double 和 Long 类型不推荐直接转换为 Char?

在 Kotlin 中,::class.simpleName是做什么的?

如何从kotlin中的ArrayList中删除所有元素

如何在kotlin中使用协程每秒调用一个函数

Kotlin 枚举中的循环引用

Foo::class.java 和 Foo::javaClass 有什么区别?

Kotlin 的类型具体化使哪些在 Java 或 Scala 中无法实现的成为可能?

在调用Kotlin数据类中的超类构造函数之前访问函数

使用范围的稀疏sparse值列表

不推荐使用仅限生命周期的LifecycleEvent

Android studio 4.0 新更新版本说 Kotlin 与这个新版本不兼容

如何在 Kotlin 中按字母顺序对字符串进行排序

在 intelliJ 元素中集成 Kotlinx 协程