【发布时间】:2021-04-14 14:50:23
【问题描述】:
我有一个 SQLite 数据库并执行以下查询:
SELECT
category,
name,
COUNT(side.id) as nb
FROM main
LEFT JOIN side
ON main.id = side.id_main
WHERE category != 3
GROUP BY category, name;
此查询大约需要 0.3 秒并返回 8000 行。 以下是相关的查询计划:
id parent notused detail
7 0 0 SCAN TABLE main USING COVERING INDEX idx_main
19 0 0 SEARCH TABLE side USING AUTOMATIC COVERING INDEX (id_main=?)
现在,我只想选择一个类别。所以,我像这样重写了我的WHERE 子句:
SELECT
category,
name,
COUNT(side.id) as nb
FROM main
LEFT JOIN side
ON main.id = side.id_main
WHERE category = 1
GROUP BY category, name;
这个查询现在大约需要 43 秒并返回 5000 行!它长了100倍! 以下是相关的查询计划:
id parent notused detail
7 0 0 SEARCH TABLE main USING COVERING INDEX idx_main (category=?)
11 0 0 SCAN TABLE side
为什么等于运算符这么慢?我的查询有什么问题吗?
复制步骤:
- 创建以下表格
CREATE TABLE main (
id INTEGER PRIMARY KEY AUTOINCREMENT,
category INTEGER,
name VARCHAR(64)
);
CREATE TABLE side (
id INTEGER PRIMARY KEY AUTOINCREMENT,
id_main INTEGER
);
CREATE INDEX idx_side ON side (id, id_main);
CREATE INDEX idx_main ON main (category, name);
- 使用以下 Perl 脚本填充表格
use strict;
use warnings FATAL => 'all';
use DBI;
my $dbh = DBI->connect("dbi:SQLite:dbname=file.db","","");
my $v = 'A';
for my $i (1..9000) {
my $category = 1;
$category = 2 if $i > 5000;
$category = 3 if $i > 8000;
$dbh->do("INSERT INTO main(category, name) VALUES($category, '$v')");
$v++;
}
for my $i (1..100000) {
my $r = int(rand() * 9000 + 1);
$dbh->do("INSERT INTO side(id_main) VALUES($r)");
}
【问题讨论】:
-
嗨皮埃尔,请更新帖子,说明“!=”和“=”查询的计划。在这里你可以找到如何获得那些sqlite.org/eqp.html
-
是的,请在两个查询上运行
EXPLAIN。你所看到的对我来说似乎非常违反直觉(但对一个好问题 +1)。 -
@ekochergin 完成。