perf: optimize historical communication fallback

This commit is contained in:
plx
2026-08-14 12:30:01 +00:00
parent 91ba85fc92
commit 89017f71a6
4 changed files with 225 additions and 6 deletions

View File

@@ -214,12 +214,114 @@ def _list_message_backed_chatwoot_items_for_opportunity(opportunity_id: str, lim
if not str(opportunity_id or "").strip():
return []
with engine.begin() as conn:
rows = conn.execute(text("""
candidate_sql = """
SELECT m.id AS message_id
FROM opp JOIN messages m
ON m.source_system = 'chatwoot'
AND NULLIF(opp.conversation_id, '') IS NOT NULL
AND m.conversation_id = opp.conversation_id
UNION
SELECT m.id
FROM opp JOIN raw_events re
ON NULLIF(opp.conversation_id, '') IS NOT NULL
AND re.conversation_id = opp.conversation_id
JOIN messages m ON m.source_system = 'chatwoot' AND m.raw_event_id = re.id
UNION
SELECT m.id
FROM opp JOIN raw_events re
ON NULLIF(opp.conversation_id, '') IS NOT NULL
AND re.conversation_id = opp.conversation_id
JOIN messages m ON m.source_system = 'chatwoot' AND m.id = re.message_id
UNION
SELECT m.id
FROM opp JOIN tasks t ON t.opportunity_id = opp.id
JOIN messages m ON m.source_system = 'chatwoot' AND m.id = t.message_id
UNION
SELECT m.id
FROM opp JOIN tasks t ON t.opportunity_id = opp.id
JOIN messages m ON m.source_system = 'chatwoot' AND m.raw_event_id = t.raw_event_id
UNION
SELECT m.id
FROM opp JOIN tasks t ON t.opportunity_id = opp.id
JOIN raw_events re ON re.id = t.raw_event_id
JOIN messages m ON m.source_system = 'chatwoot' AND m.id = re.message_id
UNION
SELECT m.id
FROM opp JOIN tasks t ON t.opportunity_id = opp.id
JOIN action_runs ar ON ar.id = t.action_run_id
JOIN messages m ON m.source_system = 'chatwoot' AND m.id = ar.message_id
UNION
SELECT m.id
FROM opp JOIN tasks t ON t.opportunity_id = opp.id
JOIN action_runs ar ON ar.id = t.action_run_id
JOIN messages m ON m.source_system = 'chatwoot' AND m.raw_event_id = ar.raw_event_id
UNION
SELECT m.id
FROM opp JOIN tasks t ON t.opportunity_id = opp.id
JOIN action_runs ar ON ar.id = t.action_run_id
JOIN raw_events re ON re.id = ar.raw_event_id
JOIN messages m ON m.source_system = 'chatwoot' AND m.id = re.message_id
"""
params = {"opportunity_id": opportunity_id, "limit": max(1, int(limit or 20))}
possible = conn.execute(text(f"""
WITH opp AS (
SELECT id, conversation_id FROM opportunities
WHERE id = CAST(:opportunity_id AS UUID) LIMIT 1
), candidate_message_ids AS ({candidate_sql})
SELECT EXISTS (SELECT 1 FROM candidate_message_ids LIMIT 1)
"""), params).scalar()
if not possible:
return []
detail_sql = """
WITH opp AS (
SELECT id, conversation_id, contact_id
FROM opportunities
WHERE id = CAST(:opportunity_id AS UUID)
LIMIT 1
), candidate_message_ids AS (
__CANDIDATE_SQL__
), candidate_messages AS (
SELECT m.* FROM messages m
JOIN candidate_message_ids candidate ON candidate.message_id = m.id
), message_raw_pairs AS (
SELECT m.id AS message_id, re.id AS raw_event_id
FROM candidate_messages m JOIN raw_events re ON re.id = m.raw_event_id
UNION
SELECT m.id, re.id
FROM candidate_messages m JOIN raw_events re ON re.message_id = m.id
), raw_context AS (
SELECT m.id AS message_id, pair.raw_event_id
FROM candidate_messages m
LEFT JOIN message_raw_pairs pair ON pair.message_id = m.id
), action_pairs AS (
SELECT context.message_id, context.raw_event_id, ar.id AS action_run_id
FROM raw_context context JOIN action_runs ar ON ar.message_id = context.message_id
UNION
SELECT context.message_id, context.raw_event_id, ar.id
FROM raw_context context JOIN action_runs ar ON ar.raw_event_id = context.raw_event_id
), action_context AS (
SELECT context.message_id, context.raw_event_id, pair.action_run_id
FROM raw_context context
LEFT JOIN action_pairs pair
ON pair.message_id = context.message_id
AND pair.raw_event_id IS NOT DISTINCT FROM context.raw_event_id
), task_pairs AS (
SELECT context.message_id, context.raw_event_id, context.action_run_id, t.id AS task_id
FROM action_context context JOIN tasks t ON t.message_id = context.message_id
UNION
SELECT context.message_id, context.raw_event_id, context.action_run_id, t.id
FROM action_context context JOIN tasks t ON t.raw_event_id = context.raw_event_id
UNION
SELECT context.message_id, context.raw_event_id, context.action_run_id, t.id
FROM action_context context JOIN tasks t ON t.action_run_id = context.action_run_id
), full_context AS (
SELECT context.message_id, context.raw_event_id, context.action_run_id, pair.task_id
FROM action_context context
LEFT JOIN task_pairs pair
ON pair.message_id = context.message_id
AND pair.raw_event_id IS NOT DISTINCT FROM context.raw_event_id
AND pair.action_run_id IS NOT DISTINCT FROM context.action_run_id
), ranked AS (
SELECT DISTINCT ON (m.id)
m.id::text AS id,
@@ -271,10 +373,11 @@ def _list_message_backed_chatwoot_items_for_opportunity(opportunity_id: str, lim
m.created_at,
m.created_at AS updated_at
FROM opp
JOIN messages m ON m.source_system = 'chatwoot'
LEFT JOIN raw_events re ON re.id = m.raw_event_id OR re.message_id = m.id
LEFT JOIN action_runs ar ON ar.message_id = m.id OR ar.raw_event_id = re.id
LEFT JOIN tasks t ON t.message_id = m.id OR t.raw_event_id = re.id OR t.action_run_id = ar.id
JOIN full_context context ON TRUE
JOIN candidate_messages m ON m.id = context.message_id
LEFT JOIN raw_events re ON re.id = context.raw_event_id
LEFT JOIN action_runs ar ON ar.id = context.action_run_id
LEFT JOIN tasks t ON t.id = context.task_id
WHERE
t.opportunity_id = opp.id
OR (
@@ -287,7 +390,8 @@ def _list_message_backed_chatwoot_items_for_opportunity(opportunity_id: str, lim
FROM ranked
ORDER BY created_at DESC
LIMIT :limit
"""), {"opportunity_id": opportunity_id, "limit": max(1, int(limit or 20))}).mappings().all()
""".replace("__CANDIDATE_SQL__", candidate_sql)
rows = conn.execute(text(detail_sql), params).mappings().all()
return [dict(row) for row in rows]

View File

@@ -295,6 +295,13 @@ def ensure_core_schema() -> None:
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_raw_events_created_at ON raw_events(created_at DESC)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_raw_events_conversation ON raw_events(conversation_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_messages_conversation ON messages(conversation_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_messages_raw_event ON messages(raw_event_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_raw_events_message ON raw_events(message_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_action_runs_message ON action_runs(message_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_action_runs_raw_event ON action_runs(raw_event_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_tasks_message ON tasks(message_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_tasks_raw_event ON tasks(raw_event_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_tasks_action_run ON tasks(action_run_id)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_action_runs_created_at ON action_runs(created_at DESC)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_task_events_task ON task_events(task_id, created_at DESC)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_business_events_created_at ON business_events(created_at DESC)"))