Performance 了解复杂SQL联接的性能

Performance 了解复杂SQL联接的性能,performance,sqlite,join,subquery,big-o,Performance,Sqlite,Join,Subquery,Big O,我试图通过重新构造查询来理解我在SQLite数据库上解决的性能问题 查询的任务是筛选协议最新修订的列表。此外,某些协议可能不会发布,这将从搜索中排除。表的建模如下所示: -- Describe PROTOCOL CREATE TABLE protocol ( id CHAR(36) NOT NULL, revision CHAR(36) NOT NULL, timestamp DATETIME, name TEXT, PRIMARY KEY (revision) )

我试图通过重新构造查询来理解我在SQLite数据库上解决的性能问题

查询的任务是筛选协议最新修订的列表。此外,某些协议可能不会发布,这将从搜索中排除。表的建模如下所示:

-- Describe PROTOCOL
CREATE TABLE protocol (
  id CHAR(36) NOT NULL, 
  revision CHAR(36) NOT NULL, 
  timestamp DATETIME,
  name TEXT, 
  PRIMARY KEY (revision)
)

-- Describe PROTOCOLSTATUS
CREATE TABLE protocolstatus (
  uuid CHAR(36) NOT NULL, 
  status TEXT, 
  timestamp DATETIME, 
  protocol_id CHAR(36) NOT NULL, 
  PRIMARY KEY (uuid), 
  FOREIGN KEY(protocol_id) REFERENCES protocol (revision)
)
protocolstatus
中的条目数可以预期为
协议
中条目数的常数倍(
#p
),即使随着时间的推移,该常数可能会变得更大

在一个有300个协议和900个状态的数据库中,执行较慢的查询大约需要4秒钟。我还注意到,如果我不使用distinct,结果会重复很多次

使用子查询重新构造查询将整个过程加快到可行的响应时间(显示这些查询的输出)。
-- slow query: O((#p)^4) ?, Run Time: real 4.335 user 4.331110 sys 0.005220

SELECT DISTINCT
  protocol.id AS protocol_id,
  protocol.revision AS protocol_revision,
  protocol.timestamp AS protocol_timestamp
FROM
  protocolstatus, -- O(#p) |
  protocol -- O(#p)        | => O(#p^2) entries

JOIN (
  SELECT
    protocol.id AS id, max(protocol.timestamp) AS ts_max 
  FROM protocol
  GROUP BY protocol.id
) AS anon_1 -- O(#p)
ON protocol.timestamp = anon_1.ts_max

JOIN (
  SELECT
    max(protocolstatus.timestamp) AS max_1,
    protocolstatus.protocol_id AS protocol_id 
  FROM protocolstatus
  GROUP BY protocolstatus.protocol_id
) AS anon_2 -- O(#p)
ON protocol.revision = anon_2.protocol_id 

WHERE
  protocolstatus.status = 'approved'
  AND lower(protocol.name) LIKE lower('%c%')

ORDER BY protocol.name;
-- fast query: O(#p^3)? Run Time: real 0.042 user 0.041540 sys 0.000767
SELECT
  protocol.id AS protocol_id,
  protocol.revision AS protocol_revision,
  protocol.timestamp AS protocol_timestamp
FROM protocol -- O(#p)

JOIN (
  SELECT
    protocol.id AS id,
    max(protocol.timestamp) AS ts_max 
  FROM protocol
  GROUP BY protocol.id
) AS anon_1  -- query: O(#p), results: O(#p)
ON protocol.timestamp = anon_1.ts_max 

JOIN (
  SELECT
    protocolstatus.protocol_id AS protocol_id,
    protocolstatus.status AS status,
    protocolstatus.timestamp AS timestamp 
  FROM protocolstatus -- O(#p)

  JOIN (
    SELECT
      max(protocolstatus.timestamp) AS timestamp,
      protocolstatus.protocol_id AS protocol_id 
    FROM protocolstatus
    GROUP BY protocolstatus.protocol_id
  ) AS anon_3 -- O(#p)
  ON protocolstatus.timestamp = anon_3.timestamp 

  WHERE protocolstatus.status = "approved"
) AS anon_2 -- query: O(#p^2), results: O(#p)
ON protocol.revision = anon_2.protocol_id 

WHERE lower(protocol.name) LIKE lower("%c%") ORDER BY protocol.name;
0|Trace|0|0|0||00|
1|Integer|48|1|0||00|
2|Once|0|48|0||00|
3|OpenEphemeral|2|2|0||00|
4|Noop|0|0|0||00|
5|Integer|0|6|0||00|
6|Integer|0|5|0||00|
7|Null|0|9|9||00|
8|Gosub|8|44|0||00|
9|Goto|0|161|0||00|
10|OpenRead|3|18|0|3|00|
11|OpenRead|7|21|0|k(2,B,B)|00|
12|Rewind|7|29|11|0|00|
13|IdxRowid|7|11|0||00|
14|Seek|3|11|0||00|
15|Column|7|0|10||00|
16|Compare|9|10|1|k(1,B)|00|
17|Jump|18|22|18||00|
18|Move|10|9|0||00|
19|Gosub|7|35|0||00|
20|IfPos|6|48|0||00|
21|Gosub|8|44|0||00|
22|Column|3|2|12||00|
23|CollSeq|13|0|0|(BINARY)|00|
24|AggStep|0|12|3|max(1)|01|
25|If|13|27|0||00|
26|Column|7|0|2||00|
27|Integer|1|5|0||00|
28|Next|7|13|0||01|
29|Close|3|0|0||00|
30|Close|7|0|0||00|
31|Gosub|7|35|0||00|
32|Goto|0|48|0||00|
33|Integer|1|6|0||00|
34|Return|7|0|0||00|
35|IfPos|5|37|0||00|
36|Return|7|0|0||00|
37|AggFinal|3|1|0|max(1)|00|
38|SCopy|2|14|0||00|
39|SCopy|3|15|0||00|
40|MakeRecord|14|2|11||00|
41|NewRowid|2|16|0||00|
42|Insert|2|11|16||08|
43|Return|7|0|0||00|
44|Null|0|2|0||00|
45|Null|0|4|0||00|
46|Null|0|3|0||00|
47|Return|8|0|0||00|
48|Return|1|0|0||00|
49|Integer|100|17|0||00|
50|Once|1|100|0||00|
51|OpenEphemeral|4|2|0||00|
52|SorterOpen|8|3|0|k(1,B)|00|
53|Integer|0|22|0||00|
54|Integer|0|21|0||00|
55|Null|0|25|25||00|
56|Gosub|24|96|0||00|
57|OpenRead|5|24|0|4|00|
58|Rewind|5|65|0||00|
59|Column|5|3|27||00|
60|Sequence|8|28|0||00|
61|Column|5|2|29||00|
62|MakeRecord|27|3|30||00|
63|SorterInsert|8|30|0||00|
64|Next|5|59|0||01|
65|Close|5|0|0||00|
66|OpenPseudo|9|30|3||00|
67|SorterSort|8|100|0||00|
68|SorterData|8|30|0||00|
69|Column|9|0|26||20|
70|Compare|25|26|1|k(1,B)|00|
71|Jump|72|76|72||00|
72|Move|26|25|0||00|
73|Gosub|23|87|0||00|
74|IfPos|22|100|0||00|
75|Gosub|24|96|0||00|
76|Column|9|2|27||00|
77|CollSeq|31|0|0|(BINARY)|00|
78|AggStep|0|27|18|max(1)|01|
79|If|31|81|0||00|
80|Column|9|0|19||00|
81|Integer|1|21|0||00|
82|SorterNext|8|68|0||00|
83|Gosub|23|87|0||00|
84|Goto|0|100|0||00|
85|Integer|1|22|0||00|
86|Return|23|0|0||00|
87|IfPos|21|89|0||00|
88|Return|23|0|0||00|
89|AggFinal|18|1|0|max(1)|00|
90|SCopy|18|32|0||00|
91|SCopy|19|33|0||00|
92|MakeRecord|32|2|34||00|
93|NewRowid|4|35|0||00|
94|Insert|4|34|35||08|
95|Return|23|0|0||00|
96|Null|0|19|0||00|
97|Null|0|20|0||00|
98|Null|0|18|0||00|
99|Return|24|0|0||00|
100|Return|17|0|0||00|
101|SorterOpen|10|3|0|k(1,B)|00|
102|OpenEphemeral|11|0|0|k(3,B,B,B)|08|
103|OpenRead|0|24|0|2|00|
104|OpenRead|1|18|0|5|00|
105|OpenRead|12|19|0|k(1,B)|00|
106|Once|2|114|0||00|
107|OpenAutoindex|13|2|0|k(2,B,B)|00|
108|Rewind|0|114|0||00|
109|Column|0|1|37||00|
110|Rowid|0|38|0||00|
111|MakeRecord|37|2|36|ad|00|
112|IdxInsert|13|36|0||10|
113|Next|0|109|0||03|
114|String8|0|39|0|approved|00|
115|SeekGe|13|147|39|1|00|
116|IdxGE|13|147|39|1|01|
117|Rewind|4|146|0||00|
118|Column|4|1|40||00|
119|IsNull|40|145|0||00|
120|SeekGe|12|145|40|1|00|
121|IdxGE|12|145|40|1|01|
122|IdxRowid|12|36|0||00|
123|Seek|1|36|0||00|
124|Column|1|4|37||00|
125|Function|0|37|43|lower(1)|01|
126|Function|1|42|41|like(2)|02|
127|IfNot|41|145|1||00|
128|Rewind|2|145|0||00|
129|Column|1|2|41||00|
130|Column|2|1|44||00|
131|Ne|44|144|41|(BINARY)|6b|
132|Column|1|0|45||00|
133|Column|12|0|46||00|
134|Column|1|2|47||00|
135|Found|11|144|45|3|00|
136|MakeRecord|45|3|44||00|
137|IdxInsert|11|44|0||00|
138|MakeRecord|45|3|44||00|
139|Column|1|4|48||00|
140|Sequence|10|49|0||00|
141|Move|44|50|0||00|
142|MakeRecord|48|3|41||00|
143|SorterInsert|10|41|0||00|
144|Next|2|129|0||01|
145|Next|4|118|0||01|
146|Next|13|116|0||00|
147|Close|1|0|0||00|
148|Close|12|0|0||00|
149|OpenPseudo|14|44|3||00|
150|OpenPseudo|15|51|3||00|
151|SorterSort|10|159|0||00|
152|SorterData|10|51|0||00|
153|Column|15|2|44||20|
154|Column|14|0|45||20|
155|Column|14|1|46||00|
156|Column|14|2|47||00|
157|ResultRow|45|3|0||00|
158|SorterNext|10|152|0||00|
159|Close|14|0|0||00|
160|Halt|0|0|0||00|
161|Transaction|0|0|0||00|
162|VerifyCookie|0|29|0||00|
163|TableLock|0|18|0|protocol|00|
164|TableLock|0|24|0|protocolstatus|00|
165|String8|0|52|0|%c%|00|
166|Function|1|52|42|lower(1)|01|
167|Goto|0|10|0||00|
0|Trace|0|0|0||00|
1|Integer|48|1|0||00|
2|Once|0|48|0||00|
3|OpenEphemeral|1|2|0||00|
4|Noop|0|0|0||00|
5|Integer|0|6|0||00|
6|Integer|0|5|0||00|
7|Null|0|9|9||00|
8|Gosub|8|44|0||00|
9|Goto|0|163|0||00|
10|OpenRead|2|18|0|3|00|
11|OpenRead|8|21|0|k(2,B,B)|00|
12|Rewind|8|29|11|0|00|
13|IdxRowid|8|11|0||00|
14|Seek|2|11|0||00|
15|Column|8|0|10||00|
16|Compare|9|10|1|k(1,B)|00|
17|Jump|18|22|18||00|
18|Move|10|9|0||00|
19|Gosub|7|35|0||00|
20|IfPos|6|48|0||00|
21|Gosub|8|44|0||00|
22|Column|2|2|12||00|
23|CollSeq|13|0|0|(BINARY)|00|
24|AggStep|0|12|3|max(1)|01|
25|If|13|27|0||00|
26|Column|8|0|2||00|
27|Integer|1|5|0||00|
28|Next|8|13|0||01|
29|Close|2|0|0||00|
30|Close|8|0|0||00|
31|Gosub|7|35|0||00|
32|Goto|0|48|0||00|
33|Integer|1|6|0||00|
34|Return|7|0|0||00|
35|IfPos|5|37|0||00|
36|Return|7|0|0||00|
37|AggFinal|3|1|0|max(1)|00|
38|SCopy|2|14|0||00|
39|SCopy|3|15|0||00|
40|MakeRecord|14|2|11||00|
41|NewRowid|1|16|0||00|
42|Insert|1|11|16||08|
43|Return|7|0|0||00|
44|Null|0|2|0||00|
45|Null|0|4|0||00|
46|Null|0|3|0||00|
47|Return|8|0|0||00|
48|Return|1|0|0||00|
49|Gosub|1|2|0||00|
50|Integer|101|17|0||00|
51|Once|1|101|0||00|
52|OpenEphemeral|5|2|0||00|
53|SorterOpen|9|3|0|k(1,B)|00|
54|Integer|0|22|0||00|
55|Integer|0|21|0||00|
56|Null|0|25|25||00|
57|Gosub|24|97|0||00|
58|OpenRead|6|24|0|4|00|
59|Rewind|6|66|0||00|
60|Column|6|3|27||00|
61|Sequence|9|28|0||00|
62|Column|6|2|29||00|
63|MakeRecord|27|3|30||00|
64|SorterInsert|9|30|0||00|
65|Next|6|60|0||01|
66|Close|6|0|0||00|
67|OpenPseudo|10|30|3||00|
68|SorterSort|9|101|0||00|
69|SorterData|9|30|0||00|
70|Column|10|0|26||20|
71|Compare|25|26|1|k(1,B)|00|
72|Jump|73|77|73||00|
73|Move|26|25|0||00|
74|Gosub|23|88|0||00|
75|IfPos|22|101|0||00|
76|Gosub|24|97|0||00|
77|Column|10|2|27||00|
78|CollSeq|31|0|0|(BINARY)|00|
79|AggStep|0|27|18|max(1)|01|
80|If|31|82|0||00|
81|Column|10|0|19||00|
82|Integer|1|21|0||00|
83|SorterNext|9|69|0||00|
84|Gosub|23|88|0||00|
85|Goto|0|101|0||00|
86|Integer|1|22|0||00|
87|Return|23|0|0||00|
88|IfPos|21|90|0||00|
89|Return|23|0|0||00|
90|AggFinal|18|1|0|max(1)|00|
91|SCopy|18|32|0||00|
92|SCopy|19|33|0||00|
93|MakeRecord|32|2|34||00|
94|NewRowid|5|35|0||00|
95|Insert|5|34|35||08|
96|Return|23|0|0||00|
97|Null|0|19|0||00|
98|Null|0|20|0||00|
99|Null|0|18|0||00|
100|Return|24|0|0||00|
101|Return|17|0|0||00|
102|SorterOpen|11|3|0|k(1,B)|00|
103|OpenRead|4|24|0|4|00|
104|OpenRead|0|18|0|5|00|
105|OpenRead|12|19|0|k(1,B)|00|
106|Once|2|116|0||00|
107|OpenAutoindex|13|4|0|k(4,B,B,B,B)|00|
108|Rewind|4|116|0||00|
109|Column|4|1|37||00|
110|Column|4|2|38||00|
111|Column|4|3|39||00|
112|Rowid|4|40|0||00|
113|MakeRecord|37|4|36|acad|00|
114|IdxInsert|13|36|0||10|
115|Next|4|109|0||03|
116|String8|0|41|0|approved|00|
117|SeekGe|13|149|41|1|00|
118|IdxGE|13|149|41|1|01|
119|Column|13|2|42||00|
120|IsNull|42|148|0||00|
121|SeekGe|12|148|42|1|00|
122|IdxGE|12|148|42|1|01|
123|IdxRowid|12|36|0||00|
124|Seek|0|36|0||00|
125|Column|0|4|37||00|
126|Function|0|37|45|lower(1)|01|
127|Function|1|44|43|like(2)|02|
128|IfNot|43|148|1||00|
129|Rewind|1|148|0||00|
130|Column|0|2|43||00|
131|Column|1|1|46||00|
132|Ne|46|147|43|(BINARY)|6b|
133|Rewind|5|147|0||00|
134|Column|13|1|47||00|
135|Column|5|0|48||00|
136|Ne|48|146|47|(BINARY)|6b|
137|Column|0|0|49||00|
138|Column|12|0|50||00|
139|Column|0|2|51||00|
140|MakeRecord|49|3|48||00|
141|Column|0|4|38||00|
142|Sequence|11|39|0||00|
143|Move|48|40|0||00|
144|MakeRecord|38|3|47||00|
145|SorterInsert|11|47|0||00|
146|Next|5|134|0||01|
147|Next|1|130|0||01|
148|Next|13|118|0||00|
149|Close|0|0|0||00|
150|Close|12|0|0||00|
151|OpenPseudo|14|48|3||00|
152|OpenPseudo|15|52|3||00|
153|SorterSort|11|161|0||00|
154|SorterData|11|52|0||00|
155|Column|15|2|48||20|
156|Column|14|0|49||20|
157|Column|14|1|50||00|
158|Column|14|2|51||00|
159|ResultRow|49|3|0||00|
160|SorterNext|11|154|0||00|
161|Close|14|0|0||00|
162|Halt|0|0|0||00|
163|Transaction|0|0|0||00|
164|VerifyCookie|0|29|0||00|
165|TableLock|0|18|0|protocol|00|
166|TableLock|0|24|0|protocolstatus|00|
167|String8|0|53|0|%c%|00|
168|Function|1|53|44|lower(1)|01|
169|Goto|0|10|0||00|