Skip to content

[dataquery] Fetch accessible instruments in a single query in the dictionary module - #11167

Merged
driusan merged 2 commits into
aces:29.0-releasefrom
HenriRabalais:dataquery-dictionary-visit-query-perf
Oct 13, 2026
Merged

driusan merged 2 commits into
aces:29.0-releasefrom
HenriRabalais:dataquery-dictionary-visit-query-perf

Conversation

@HenriRabalais

@HenriRabalais HenriRabalais commented Aug 10, 2026 •

Copy link
Copy Markdown
Collaborator

Description

/dictionary/categories (and /dictionary/module/<name>) scaled linearly with the number of distinct visit labels in the database. getUserModuleCategories() built the set of instruments the user can access by running one Utility::getVisitInstruments() query per visit label, and each of those queries joins session, candidate, flag and test_names.

This replaces the per-visit loop with a single query that fetches the distinct instrument names across all of the user's visits. The query returns names only, since the result is only used to check whether an instrument is in the list.

Changes

  • Replaced the per-visit foreach loop in LORIS\dictionary\Module::getUserModuleCategories() with a single query over all of the user's visits
  • The query returns Test_name only, so Full_name is no longer fetched

Testing Instructions

  1. Use a database with a large number of distinct session.Visit_label values.
  2. Log in and open the Data Query Tool, or request GET /dictionary/categories directly.
  3. Confirm the endpoint now returns quickly rather than blocking for tens of seconds.
  4. Confirm the instrument categories shown in the tool are the same as before this change (the response body should be identical).

Related Issues

Closes #11166. The slow loop was introduced in #9903.

@github-actions github-actions Bot added Language: PHP PR or issue that update PHP code Module: dictionary PR or issue related to (new) dictionary module labels Aug 10, 2026
@HenriRabalais
HenriRabalais force-pushed the dataquery-dictionary-visit-query-perf branch from 667b993 to 429e3fc Compare August 10, 2026 23:24
@HenriRabalais HenriRabalais added Module: dataquery PR or issue related to (new) dataquery module and removed Module: dictionary PR or issue related to (new) dictionary module labels Aug 11, 2026
@HenriRabalais
HenriRabalais force-pushed the dataquery-dictionary-visit-query-perf branch from 429e3fc to 32fa8b6 Compare August 11, 2026 10:09
@github-actions github-actions Bot added the Module: dictionary PR or issue related to (new) dictionary module label Aug 11, 2026
@HenriRabalais

Copy link
Copy Markdown
Collaborator Author

@marandmart can you take a look at this when you have the time?

@ridz1208

Copy link
Copy Markdown
Collaborator

@HenriRabalais can you please rebase this to 29.0-release

Move the per-visit instrument lookup out of the dictionary module and into
a batched Utility::getVisitsInstruments() helper that fetches the distinct
instruments for all of the users visits in one query, instead of running
Utility::getVisitInstruments() once per visit label.
@ridz1208 ridz1208 added the State: Needs rebase PR that needs to be rebased to proceed (conflicts, wrong branch...) label Aug 19, 2026
@HenriRabalais
HenriRabalais force-pushed the dataquery-dictionary-visit-query-perf branch from 32fa8b6 to babdda2 Compare August 19, 2026 12:50
@github-actions github-actions Bot added Language: Javascript PR or issue that update Javascript code Module: statistics PR or issue related to statistics module Multilingual Any tasks related to making LORIS multilingual labels Aug 19, 2026
@HenriRabalais
HenriRabalais changed the base branch from main to 29.0-release August 19, 2026 12:50

@marandmart marandmart left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@HenriRabalais HenriRabalais removed the State: Needs rebase PR that needs to be rebased to proceed (conflicts, wrong branch...) label Aug 31, 2026
@driusan driusan self-assigned this Aug 31, 2026
Comment thread php/libraries/Utility.class.inc Outdated
FROM session s
JOIN candidate c ON (c.ID=s.CandidateID)
JOIN flag f ON (f.sessionID=s.id)
JOIN test_names t ON (f.TestID=t.ID)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This table is not accurate for the full name. The source of truth for the full name is NDB_BVL_Instrument::getFullName(). (For instance, for LINST instruments it comes from parsing the file, and for a php instrument it could just return a hardcoded string.)

I think you need to:

  1. Not join this table (it's unnecessary)
  2. Call the NDB_BVL_Instrument::factory(testname)->getFullName() for each

(This shouldn't be slower, unless there's too many instruments using LegacyInstrumentTrait instead of implementing getFullName() themselves..)

I also think this function should be moved into the dictionary module where it's used or inlined (not for efficiency, just because having both getVisitsInstruments and getVisitInstruments next to each other in the Utility class is confusing, and there is only one call site.. also you have access to the LorisInstance object there to get a database connection.)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@driusan

thanks for the review!

I've now realized the full name isn't used at this call site at all. getUserModuleCategories() only checks whether each instrument is in the list, and the category names already come from getFullName() in InstrumentQueryEngine::getDataDictionary(), so there's nothing to call getFullName() for. I've removed Full_name from the query. I kept the join to test_names only to get Test_name, since flag just has TestID, so let me know if you had another way of getting the name in mind.

I moved the query into getUserModuleCategories() and removed Utility::getVisitsInstruments(), as you asked.

@driusan
driusan merged commit 9d29e0e into aces:29.0-release Oct 13, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Language: Javascript PR or issue that update Javascript code Language: PHP PR or issue that update PHP code Module: dataquery PR or issue related to (new) dataquery module Module: dictionary PR or issue related to (new) dictionary module Module: statistics PR or issue related to statistics module Multilingual Any tasks related to making LORIS multilingual

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[dataquery] /dictionary/categories load time scales with the number of visit labels

4 participants