【问题标题】:Why query with "in" and "on" statement runs infinitely为什么使用“in”和“on”语句进行查询无限运行
【发布时间】:2020-06-30 16:29:06
【问题描述】:

我有三个表,table3 基本上是 table1 和 table2 的中间表。当我执行包含“in”并连接 table1 和 table3 的查询语句时,它一直在运行,我无法得到结果。如果我使用id=134 而不是id in (134,267,390,4234 ... ),就会出现结果。我不明白为什么“in”有效果,有人知道吗?

查询语句:

select count(*) from table1, table3 on id=table3.table1_id where table3.table2_id = 123 and id in (134,267,390,4234) and item = 30;

表结构:

table1:
   id integer primary key,
   item integer
   
table2:
   id integer,
   item integer

table3:
    table1_id integer,
    table2_id integer

-- the DB without index was 0.8 TB after the three indices is now 2.5 TB
indices on: table1.item, table3.table1_id, table3.table2_id

环境:Linux,sqlite 3.7.17

【问题讨论】:

  • 您的查询无法编译。 Error: no such column: table3.table1.id 我猜你的意思是table3.table1_id
  • FROM 子句应该是from table1 inner join table3 on table1.id = table3.table1_id 或带有别名:from table1 t1 inner join table3 t3 on t1.id = t3.table1_id
  • @OlivierJacot-Descombes 虽然我同意最好明确加入,from table1, table3 on id=table3.table1_idfrom table1 inner join table3 on id=table3.table1.id 在 SQLite 中是等效的。见Side note: Special handling of CROSS JOIN.
  • @Schwern 哦,不好意思,查询语句错了,我修改了

标签: sql database sqlite


【解决方案1】:

from table1, table3 在大多数数据库上是cross join,由于数据的大小,交叉连接非常庞大,但在 SQLite3 中,它是内部连接。来自SQLite SELECT docs

旁注:CROSS JOIN 的特殊处理。“INNER JOIN”、“JOIN”和“,”连接运算符之间没有区别。它们在 SQLite 中完全可以互换。

在这种特定情况下,这不是你的问题,但我们不要试探命运;总是明确地写出你的连接。

select count(*)
from table1
join table3 on id=table3.table1_id
where table3.table2_id = 123
  and id in (134,267,390,4234);

由于您只是在计数,因此您不需要 table1 中的任何数据,只需要 ID。 table3 有table1_id,所以不需要加入table1。我们可以完全使用 table3 连接表来做到这一点。

select count(*)
from table3
where table2_id = 123
  and table1_id in (134,267,390,4234);

SQLite 每个表只能使用一个索引。要在如此大的数据集上执行此操作,您需要两列的复合索引table3(table1_id, table2_id)。大概你不想要重复,所以这应该采用唯一索引的形式。这将涵盖仅针对 table1_id 的查询以及针对 table1_id 和 table2_id 的查询;您应该删除 table1_id 索引以节省空间和时间。

create unique index table3_unique on table3(table1_id, table2_id);

复合索引不会用于仅使用 table2_id 的查询,保留您现有的 table2_id 索引。

您的查询现在应该运行 lickity-split。

更多信息,请阅读SQLite Query Optimizer


1 TB 是很多的数据。虽然SQLite technicly can handle this,它可能不是最好的选择。它非常适合小型和简单的数据库,但它缺少很多功能。您应该研究一个更强大的数据库,例如PostgreSQL。它不是灵丹妙药,所有相同的原则都适用,但它更适合这种规模的数据。

【讨论】:

  • 我实际上不确定,如果 sqlite3 的反应比仅使用文件系统更好,我的意思是,只需读取所有文件。我真的很难确定我应该采用哪个数据库,MangoDB 或文件系统或 postgresql。我之前在这个帖子里写过应用描述,但是没有人回答我的问题,你能看看吗? stackoverflow.com/questions/62409573/…
  • @ErwinZangwill 你肯定不想使用文件系统,你最终会很糟糕地重新实现 SQLite。仅仅获得正确的并发访问是非常非常困难的。 MongoDB 和 NoSQL 非常适合存储“文档”。 Postgres 两全其美:它是一个功能非常强大的 SQL 数据库,但也支持需要更大灵活性的 JSON 列。您也不想在 C 中执行此操作,它是开发软件最困难的语言,您的性能问题将在数据库中。
  • @ErwinZangwill 大多数数据库都支持某种 CSV 导入工具。导入的大小和性能无关紧要;谁在乎它是否需要一周,你只会做一次。重要的是要正确处理转换和架构。像 Python、Ruby 或 Go 这样的语言会比 C 更合适。在不知道您的数据是什么样子的情况下,我不能说更多。
  • 感谢战利品!!我读到 MangDB 或一些 nosql 数据库使用 mmap 将文件预加载到内存中,因为我的 RAM 不足以将所有文件加载到内存中,我不知道它是否会比 sqlite 甚至 postgresql 执行得更好?另外,MangoDB存储了json文件,但是属性的名称不是冗余的吗?我真的不明白为什么它不只存储标题?
  • 顺便说一句。 “SQLite每个表只能使用一个索引”,所以一个表可以有多个索引但是在执行查询时,一个查询只能使用一个索引?至于“这将涵盖仅针对 table1_id 的查询以及针对 table1_id 和 table2_id 的查询”,“复合索引不适用于仅使用 table2_id 的查询,保留您现有的 table2_id 索引”为什么它会保留 table1_id 索引但不table2_id?实际上,为了进一步处理,table1_idtable2_id将分别用于查询,所以需要table2_idtable3_unique这两个索引对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-06
  • 2015-02-25
  • 2021-12-03
  • 2019-12-15
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
相关资源
最近更新 更多