繁体   English   中英

提高SQL选择和联接SQLite的效率

[英]Improving efficiency of SQL selects and joins in sqlite

我正在一个个人项目,致力于分析数据库中的文本。 我的目的是做一些有趣的事情,并了解SQL和sqlite。 因此,考虑到我的新手能力,我希望获得有关更有效地执行此操作的建议。

举例来说,我想在文章A挑选食物的类型。 我解析我的文章,如果找到食物F ,则将F添加到表项中 然后我将A.idF.id添加到results中 当我解析文章并找到项目中已经存在的食物G ,我要做的就是在结果中添加A.idG.id

因此,我的架构如下所示:

  • 文章: id, article
  • 结果: id, item_id, article_id
  • 项目: id, foodtype, food

如果我想找到所有有关orangesgrapes和任何vegetable ,那么我将从以下内容开始:

SELECT * 
  FROM articles 
INNER JOIN results ON articles.id = results.article_id  
INNER JOIN items ON results.item_id = items.id

并添加:

WHERE foodtype='vegetable' OR food='orange' OR food='grape'

实际上,我的数据库更大。 有成千上万的文章和十万多种提取的“食物”。 我将3个表加入其中的大多数查询都不会返回,即使我将结果限制为100个结果也是如此。 我尝试在WHERE子句中常见的字段(例如foodfoodtype上创建索引,但是没有任何改善。

我可以对数据库或查询进行哪些改进?

只检索您需要的列

查询的第一个问题是SELECT *从查询中联接的所有表中返回所有列。 这意味着将返回评估两侧的JOIN标准中的值。 最好写出所需的实际列,因为列出的所有三列都有一个id列-除非使用顺序位置(否则不是很好的做法-更改位置,否则数据检索就不应该了),这会使正确的值检索变得复杂)。

使用表别名可以最大程度地减少引用特定表所需的内容:

SELECT a.article 
  FROM ARTICLES a
  JOIN RESULTS r ON r.article_id = a.id
  JOIN ITEMS i ON i.id = r.item_id

索引编制

索引外键-用于JOIN条件的索引应该是表主键之后列表中的第二件事。

然后,您必须定期运行ANALYZE命令,因为统计信息是...

...不会随着数据库内容的更改而自动更新。 如果数据库的内容发生重大变化,或者数据库架构发生变化,则应考虑重新运行ANALYZE命令以更新统计信息。

这些统计信息是优化程序用于查询决策的内容,以及索引的存在。

众所周知,OR对性能不利

您可以尝试重新编写查询,以便它不与UNION一起使用OR:

SELECT a.article 
  FROM ARTICLES a
  JOIN RESULTS r ON r.article_id = a.id
  JOIN ITEMS i ON i.id = r.item_id
 WHERE i.foodtype = 'vegetable'
UNION 
SELECT a.article 
  FROM ARTICLES a
  JOIN RESULTS r ON r.article_id = a.id
  JOIN ITEMS i ON i.id = r.item_id
 WHERE i.food IN ('orange', 'grape')

请注意, UNIONUNION ALL慢,因为UNION会删除重复项。 UNION ALL更快,因为它不会删除重复项。

首先SELECT *是邪恶的。 无论您构建多少索引,查询都将不被覆盖(除非您对整个表建立索引,这将使索引扫描和表扫描的开销相同)。 1.因此,在要显示的列上选择。 2.在id列上添加约束索引。3.在WHERE子句中的列上添加非聚集索引。4.在选择查询的列上放置覆盖索引。

调整查询的最佳方法是查看执行计划并查看瓶颈步骤,但是由于您的问题中没有瓶颈,这是我能做的最佳猜测

这些查询在SQLite中可以非常快。 我正在做可比的事情

FOODTYPE
foodtypeid integer primary key
foodtypedesc  text

FOOD
foodid integer primary key
foodtypeid integer (indexed)
fooddesc text (indexed)

ARTICLE
articleid integer primary key 
title


ARTICLEFOOD
id integer primary key autoincrement
articleid integer   (indexed)
foodid integer      (indexed)
foodtypeid integer  (indexed) [EDIT: forgot to add this column yesterday)

注意:所有主键都已建立索引,标记为索引的列也应建立索引。

 select title, foodesc, foodtypedesc
 from articlefood AF
 join article A on AF.articleid=A.articleid
 join FOOD F on AF.foodid = F.foodid and fooddesc
 join FOODTYPE FT on FT.foodtypeid = F.foodtypeid 
 where .....

或者您可以使用内联视图,如果有合适的索引,这些视图在SQLite中也可以非常快。 以下查询将返回与指定食物和指定食物类型匹配的所有商品ID。 UNION的默认行为是消除重复的行,并且由于我们仅要求提供商品ID(目的是将某些商品加入此ID列表),因此以下查询将产生一组符合条件的独特商品ID:

 select articleid from  ARTICLEFOOD 
 JOIN
 (
    select foodid from FOOD where  .... 
 ) as MyFoods
 ON ARTICLEFOOD.foodid = MyFoods.foodid

 UNION

 select articleid from  ARTICLEFOOD 
 JOIN
 (
    select foodtypeid from FOODTYPE where  .... 
 ) as MyFoodTypes
 ON ARTICLEFOOD.foodtypeid = MyFoodTypes.foodtypeid

提姆

始终先内部连接最小的表。 我怀疑您可能没有文章那么多(也许?)。 因此应该是“小内连接大内连接最大”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM