Skip to content

Commit c3168de

Browse files
Merge pull request #623 from sgrif/sg-optimize-reverse-dependencies
Optimize the reverse dependencies endpoint
2 parents 3c14e8a + 1122ab6 commit c3168de

File tree

4 files changed

+48
-29
lines changed

4 files changed

+48
-29
lines changed
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DROP INDEX dependencies_crate_id_version_id_idx;

Diff for: migrations/20170312165531_index_dependencies/up.sql

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CREATE INDEX ON dependencies (crate_id, version_id);

Diff for: src/krate.rs

+9-29
Original file line numberDiff line numberDiff line change
@@ -566,38 +566,18 @@ impl Crate {
566566
offset: i64,
567567
limit: i64)
568568
-> CargoResult<(Vec<(Dependency, String, i32)>, i64)> {
569-
let select_sql = "
570-
FROM dependencies
571-
INNER JOIN (
572-
SELECT versions.*,
573-
row_number() OVER (PARTITION BY crate_id ORDER BY to_semver_no_prerelease(num) DESC NULLS LAST) rn
574-
FROM versions
575-
WHERE NOT yanked
576-
) versions
577-
ON versions.id = dependencies.version_id
578-
INNER JOIN crates
579-
ON crates.id = versions.crate_id
580-
WHERE dependencies.crate_id = $1
581-
AND rn = 1
582-
";
583-
let fetch_sql = format!("SELECT DISTINCT ON (crate_downloads, crate_name)
584-
dependencies.*,
585-
crates.downloads AS crate_downloads,
586-
crates.name AS crate_name
587-
{}
588-
ORDER BY crate_downloads DESC
589-
OFFSET $2
590-
LIMIT $3",
591-
select_sql);
592-
let count_sql = format!("SELECT COUNT(DISTINCT(crates.id)) {}", select_sql);
593-
594-
let stmt = conn.prepare(&fetch_sql)?;
595-
let vec: Vec<_> = stmt.query(&[&self.id, &offset, &limit])?
569+
let stmt = conn.prepare(include_str!("krate_reverse_dependencies.sql"))?;
570+
571+
let rows = stmt.query(&[&self.id, &offset, &limit])?;
572+
let cnt = if rows.is_empty() {
573+
0i64
574+
} else {
575+
rows.get(0).get("total")
576+
};
577+
let vec: Vec<_> = rows
596578
.iter()
597579
.map(|r| (Model::from_row(&r), r.get("crate_name"), r.get("crate_downloads")))
598580
.collect();
599-
let stmt = conn.prepare(&count_sql)?;
600-
let cnt: i64 = stmt.query(&[&self.id])?.iter().next().unwrap().get(0);
601581

602582
Ok((vec, cnt))
603583
}

Diff for: src/krate_reverse_dependencies.sql

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
-- Apply pagination to the whole thing
2+
SELECT *, COUNT(*) OVER () as total FROM (
3+
-- Multple dependencies can exist, make it distinct
4+
SELECT DISTINCT ON (crate_downloads, crate_name)
5+
dependencies.*,
6+
crates.downloads AS crate_downloads,
7+
crates.name AS crate_name
8+
FROM dependencies
9+
-- We only want the crates whose *max* version is dependent, so we join on a
10+
-- subselect that includes the versions with their ordinal position
11+
INNER JOIN (
12+
SELECT versions.*,
13+
row_number() OVER (
14+
PARTITION BY crate_id
15+
ORDER BY to_semver_no_prerelease(num) DESC NULLS LAST
16+
) rn
17+
FROM versions
18+
WHERE NOT yanked
19+
-- This is completely redundant, but it's faster to filter the versions
20+
-- early even if this subselect is done via an index scan.
21+
AND crate_id = ANY(
22+
SELECT versions.crate_id
23+
FROM versions
24+
INNER JOIN dependencies
25+
ON dependencies.version_id = versions.id
26+
WHERE dependencies.crate_id = $1
27+
)
28+
) versions
29+
ON versions.id = dependencies.version_id
30+
INNER JOIN crates
31+
ON crates.id = versions.crate_id
32+
WHERE dependencies.crate_id = $1
33+
AND rn = 1
34+
ORDER BY crate_downloads DESC
35+
) t
36+
OFFSET $2
37+
LIMIT $3

0 commit comments

Comments
 (0)