Die Berichtslinie einmal ausrechnen statt zweimal
Die Akte holte Vorgesetzte und direkte Berichte in zwei Teilabfragen, je
eine mit eigenem Filter -- in der Annahme, der Filter schraenke die
Funktion ein. Tut er nicht. om_reporting_lines traegt ein `with
recursive` im Koerper und laesst sich deshalb nicht einbetten; sie rechnet
jedes Mal alle Zeilen aus, und der Filter wirft sie danach weg.
Auf dem Server gemessen:
explain analyze select * from om_reporting_lines(current_date)
where employee_id = ...;
-> Rows Removed by Filter: 783, Execution Time: 69 ms
Und ohne Filter dieselben 60 ms. Zwei Filter hiessen also zweimal
dieselbe Rechnung, rund 120 ms je Aufruf der Akte -- der groesste
Einzelposten der Seite.
Jetzt ein Aufruf, und die Auswahl trifft der Aufrufer. Dafuer wandern
einmal alle Zeilen herueber statt neun; ueber eine Verbindung im selben
Netz kostet das den Bruchteil dessen, was die zweite Rechnung kostete.
Der Kommentar, der das Gegenteil behauptete, ist durch die Messung
ersetzt.
This commit is contained in:
@@ -33,10 +33,22 @@ export async function loadEmployeeDetail(tx: Tx, id: string, today: string = tod
|
|||||||
const g = await tx
|
const g = await tx
|
||||||
.selectNoFrom((eb) => [
|
.selectNoFrom((eb) => [
|
||||||
// Vorgesetzte und direkte Berichte stehen nirgends als Spalte — sie
|
// Vorgesetzte und direkte Berichte stehen nirgends als Spalte — sie
|
||||||
// kommen aus om_reporting_lines(). Beide schränken *in* der Funktion
|
// kommen aus om_reporting_lines().
|
||||||
// ein, es wandern also neun Zeilen über die Leitung und nicht achthundert.
|
//
|
||||||
jsonArrayFrom(berichtslinienAbfrage(eb, asOf, { employeeId: id })).as("ownLines"),
|
// **Einmal** gerufen, nicht zweimal. Hier standen zwei Teilabfragen mit
|
||||||
jsonArrayFrom(berichtslinienAbfrage(eb, asOf, { actingManagerId: id })).as("reports"),
|
// je einem Filter, in der Annahme, der Filter schränke die Funktion
|
||||||
|
// ein. Das tut er nicht: wegen des `with recursive` in ihrem Körper
|
||||||
|
// lässt sie sich nicht einbetten, sie rechnet jedes Mal alle Zeilen aus
|
||||||
|
// und der Filter wirft sie danach weg. Auf dem Server gemessen:
|
||||||
|
//
|
||||||
|
// explain analyze select * from om_reporting_lines(current_date)
|
||||||
|
// where employee_id = …;
|
||||||
|
// → Rows Removed by Filter: 783, Execution Time: 69 ms
|
||||||
|
//
|
||||||
|
// Zwei Filter hiessen also zweimal dieselbe Rechnung. Jetzt wandern
|
||||||
|
// einmal alle Zeilen herüber — ein paar hundert Kilobyte über eine
|
||||||
|
// Verbindung im selben Netz — und die Auswahl trifft der Aufrufer.
|
||||||
|
jsonArrayFrom(berichtslinienAbfrage(eb, asOf)).as("lines"),
|
||||||
|
|
||||||
jsonArrayFrom(
|
jsonArrayFrom(
|
||||||
eb
|
eb
|
||||||
@@ -110,14 +122,15 @@ export async function loadEmployeeDetail(tx: Tx, id: string, today: string = tod
|
|||||||
.executeTakeFirstOrThrow();
|
.executeTakeFirstOrThrow();
|
||||||
|
|
||||||
const orgMaps = buildOrgMaps(g.units as never, g.locations as never);
|
const orgMaps = buildOrgMaps(g.units as never, g.locations as never);
|
||||||
const line = g.ownLines[0] ?? null;
|
const line = g.lines.find((l) => l.employee_id === id) ?? null;
|
||||||
|
const reports = g.lines.filter((l) => l.acting_manager_id === id);
|
||||||
const placement = pickPlacements(g.placementRows as never, asOf).get(id) ?? null;
|
const placement = pickPlacements(g.placementRows as never, asOf).get(id) ?? null;
|
||||||
|
|
||||||
// Namen für die beteiligten Personen in einem Zug: die Vertretung, die
|
// Namen für die beteiligten Personen in einem Zug: die Vertretung, die
|
||||||
// formal zuständige Leitung und die direkten Berichte.
|
// formal zuständige Leitung und die direkten Berichte.
|
||||||
const relatedIds = Array.from(
|
const relatedIds = Array.from(
|
||||||
new Set(
|
new Set(
|
||||||
[line?.acting_manager_id, line?.formal_manager_id, ...g.reports.map((r) => r.employee_id)].filter(
|
[line?.acting_manager_id, line?.formal_manager_id, ...reports.map((r) => r.employee_id)].filter(
|
||||||
(x): x is string => Boolean(x)
|
(x): x is string => Boolean(x)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -137,7 +150,7 @@ export async function loadEmployeeDetail(tx: Tx, id: string, today: string = tod
|
|||||||
return {
|
return {
|
||||||
employee,
|
employee,
|
||||||
line,
|
line,
|
||||||
reports: g.reports,
|
reports,
|
||||||
history: g.history,
|
history: g.history,
|
||||||
dependents: g.dependents,
|
dependents: g.dependents,
|
||||||
notes: g.notes,
|
notes: g.notes,
|
||||||
|
|||||||
Reference in New Issue
Block a user