我正在开展一个专注于分析数据库中文本的个人项目。我的目的是做一些有趣的事情并了解SQL和sqlite。因此,考虑到我的新手能力,我希望得到更有效的建议。
比如说,我想在文章A
中挑选食物类型。我解析了我的文章,如果我找到了食物F
,那么我会将F
添加到表项。然后,我将A.id
和F.id
添加到结果。当我解析我的文章并找到项目中已存在的食物G
时,我所做的只是将A.id
和G.id
添加到结果
所以我的模式如下所示:
id, article
id, item_id, article_id
id, foodtype, food
如果我想找到所有谈论oranges
和grapes
以及任何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'
实际上,我的数据库要大得多。有成千上万的文章和超过十万个提取的“食物”。即使我将事物限制为100个结果,我加入3个表的大多数查询也不会返回。我尝试在我的WHERE
条款中常见的字段上创建索引,例如food
和foodtype
,但看不到任何改进。
我可以对我的数据库或查询进行哪些改进吗?
答案 0 :(得分:6)
查询的第一个问题是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 command因为统计数据是......
...不会随着数据库内容的变化而自动更新。如果数据库的内容发生重大变化,或者数据库模式发生更改,则应考虑重新运行ANALYZE命令以更新统计信息。
这些统计数据是优化程序用于查询决策的,以及索引的存在。
您可以尝试重写该查询,使其不使用带有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')
请注意UNION
比UNION ALL
慢,因为UNION
会删除重复项。 UNION ALL
更快,因为它不会删除重复项。
答案 1 :(得分:1)
所有SELECT *中的第一个是邪恶的。无论您构建多少索引,都不会覆盖查询(除非您索引整个表,然后使索引扫描和表扫描成本相同)。 1.因此,选择要显示的列。 2.在id列上添加custered index 3.在WHERE子句中的列上添加非聚簇 4.在选择查询中的列上添加覆盖索引。
调整查询的最佳方法是查看执行计划并查看瓶颈步骤,但由于问题不存在,这是我可以采取的最佳猜测
答案 2 :(得分:1)
这些查询在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的默认行为是消除重复行,并且由于我们只询问articleids(意图将某些内容加入到此列表中),因此下面的查询将导致满足条件的一组不同的文章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
添
答案 3 :(得分:0)
始终在内部加入最小的表格。我怀疑你没有物品和物品一样多(也许?)。所以它应该是“小内联合更大内连接最大”。