我的 EXPLAIN QUERY PLAN 表示将会多次扫描VIEW 下的表格;情况确实如此,我可以避免吗?
这里有一个类似于我的生产数据的人为举例,它显示了两个已组成的运动队的问题,在这个世界里,我们只信任名字以 D 开头的人,< strong> E ,或 F 。
CREATE TABLE people (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE trust (glob TEXT);
CREATE VIEW trusted_people AS
SELECT * FROM people JOIN trust ON name GLOB glob;
CREATE TABLE teams (
keeper INTEGER REFERENCES people(id),
winger INTEGER REFERENCES people(id),
scorer INTEGER REFERENCES people(id)
);
INSERT INTO people(name) VALUES ('alf'), ('bob'), ('chad'), ('don'), ('ed'), ('frank');
INSERT INTO trust(glob) VALUES ('d*'), ('e*'), ('f*');
INSERT INTO teams VALUES (1, 2, 3), (4, 5, 6);
EXPLAIN QUERY PLAN SELECT tk.name, tw.name, ts.name FROM teams
JOIN trusted_people AS tk ON teams.keeper = tk.id
JOIN trusted_people AS tw ON teams.winger = tw.id
JOIN trusted_people AS ts ON teams.scorer = ts.id
;
-- SCAN TABLE teams
-- SEARCH TABLE people USING INTEGER PRIMARY KEY (rowid=?)
-- SEARCH TABLE people USING INTEGER PRIMARY KEY (rowid=?)
-- SEARCH TABLE people USING INTEGER PRIMARY KEY (rowid=?)
-- SCAN TABLE trust
-- SCAN TABLE trust
-- SCAN TABLE trust
答案 0 :(得分:0)
通常,在关系SQL中,视图的执行效果与其基础查询一样。对于视图trusted_people
,在加入此视图时无法使用索引,因为这是派生表。因此,联合可能不会如此顺利。更糟糕的是,你加入了这个观点三次。
但是我发现我认为数据库架构中存在问题。我认为通过对teams
表进行以下更改,您可以将整个查询减少到只有两个连接:
team_id | player_id | role
1 | 1 | 'keeper'
1 | 2 | 'winger'
1 | 3 | 'scorer'
2 | 4 | 'keeper'
2 | 5 | 'winger'
2 | 6 | 'scorer'
现在,以下查询应该产生您想要的结果:
SELECT t1.*
FROM teams t1
INNER JOIN people p
ON t1.player_id = p.id
INNER JOIN trust t2
ON p.name GLOB t2.glob;
如果您想要每个团队的每个匹配玩家的CSV列表,您可以使用:
SELECT
t1.team_id,
GROUP_CONCAT(p.name) AS players
FROM teams t1
INNER JOIN people p
ON t1.player_id = p.id
INNER JOIN trust t2
ON p.name GLOB t2.glob
GROUP BY
t1.team_id;
请注意,people
和trust
之间的第二次联接仍然可以从某些索引调整中受益,但仅仅进行此更改可能会使性能保持在您可以容忍的水平。