[{"data":1,"prerenderedAt":595},["ShallowReactive",2],{"page-\u002Fblog\u002Fservicenow-gliderecord-query-performance":3},{"id":4,"title":5,"author":6,"authorUrl":7,"body":8,"date":570,"dateUpdated":570,"description":571,"dqid":570,"excerpt":572,"extension":573,"faq":574,"headline":587,"meta":588,"navigation":589,"path":590,"seo":591,"socialImage":592,"stem":593,"tags":572,"__hash__":594},"content\u002Fblog\u002Fservicenow-gliderecord-query-performance.md","ServiceNow GlideRecord Performance: 10 Query Optimization Tips","SN-Tricks","https:\u002F\u002Fsn-tricks.com\u002Fabout",{"type":9,"value":10,"toc":556},"minimark",[11,15,18,23,31,153,164,168,178,181,184,188,191,198,206,209,297,306,310,317,437,456,460,463,466,470,473,476,480,489,495,499,506,517,524,528,531,539,542,546,549,552],[12,13,14],"p",{},"GlideRecord is central to ServiceNow server-side development, but a query that feels instant with test data can become a production bottleneck when a table contains millions of rows. Slow queries do more than delay one script: they hold worker threads, increase database load, lengthen transactions, and can affect every user on the instance.",[12,16,17],{},"The best optimization is usually not a clever line of JavaScript. It is asking the database a smaller, more selective question. These ten practices help developers and administrators improve GlideRecord performance without sacrificing correctness.",[19,20,22],"h2",{"id":21},"_1-query-only-the-records-you-need","1. Query Only the Records You Need",[12,24,25,26,30],{},"Never call ",[27,28,29],"code",{},"query()"," without conditions on a large table unless a controlled maintenance task genuinely requires every record. Start with the narrowest business requirement and translate it into database filters.",[32,33,38],"pre",{"className":34,"code":35,"language":36,"meta":37,"style":37},"language-js shiki shiki-themes github-light github-light","var incident = new GlideRecord('incident');\nincident.addQuery('active', true);\nincident.addQuery('assignment_group', groupSysId);\nincident.addQuery('sys_updated_on', '>=', gs.daysAgoStart(7));\nincident.query();\n","js","",[27,39,40,73,96,111,142],{"__ignoreMap":37},[41,42,45,49,53,56,59,63,66,70],"span",{"class":43,"line":44},"line",1,[41,46,48],{"class":47},"sCydW","var",[41,50,52],{"class":51},"sKWpL"," incident ",[41,54,55],{"class":47},"=",[41,57,58],{"class":47}," new",[41,60,62],{"class":61},"se37E"," GlideRecord",[41,64,65],{"class":51},"(",[41,67,69],{"class":68},"sOTlB","'incident'",[41,71,72],{"class":51},");\n",[41,74,76,79,82,84,87,90,94],{"class":43,"line":75},2,[41,77,78],{"class":51},"incident.",[41,80,81],{"class":61},"addQuery",[41,83,65],{"class":51},[41,85,86],{"class":68},"'active'",[41,88,89],{"class":51},", ",[41,91,93],{"class":92},"sMN4m","true",[41,95,72],{"class":51},[41,97,99,101,103,105,108],{"class":43,"line":98},3,[41,100,78],{"class":51},[41,102,81],{"class":61},[41,104,65],{"class":51},[41,106,107],{"class":68},"'assignment_group'",[41,109,110],{"class":51},", groupSysId);\n",[41,112,114,116,118,120,123,125,128,131,134,136,139],{"class":43,"line":113},4,[41,115,78],{"class":51},[41,117,81],{"class":61},[41,119,65],{"class":51},[41,121,122],{"class":68},"'sys_updated_on'",[41,124,89],{"class":51},[41,126,127],{"class":68},"'>='",[41,129,130],{"class":51},", gs.",[41,132,133],{"class":61},"daysAgoStart",[41,135,65],{"class":51},[41,137,138],{"class":92},"7",[41,140,141],{"class":51},"));\n",[41,143,145,147,150],{"class":43,"line":144},5,[41,146,78],{"class":51},[41,148,149],{"class":61},"query",[41,151,152],{"class":51},"();\n",[12,154,155,156,159,160,163],{},"A condition such as ",[27,157,158],{},"active=true"," may still match hundreds of thousands of rows. Combine it with selective criteria such as a group, state, date range, or known identifier. Avoid fetching a broad result set and discarding most rows with JavaScript ",[27,161,162],{},"if"," statements inside the loop.",[19,165,167],{"id":166},"_2-filter-on-indexed-selective-fields","2. Filter on Indexed, Selective Fields",[12,169,170,171,89,174,177],{},"Indexes help the database locate matching rows without scanning an entire table. Common system fields such as ",[27,172,173],{},"sys_id",[27,175,176],{},"number",", and some reference or date fields are indexed, but the exact indexes vary by table and instance.",[12,179,180],{},"An indexed field is not automatically fast. A condition matching most of the table has low selectivity and may still require substantial work. Prefer filters that sharply reduce the candidate set, and verify indexes through the table definition rather than assuming they exist.",[12,182,183],{},"Do not add custom indexes as a first reaction. Each index consumes space and adds overhead to inserts and updates. A justified index supports a recurring, high-value query pattern—not one poorly scoped script.",[19,185,187],{"id":186},"_3-avoid-invalid-fields-in-conditions","3. Avoid Invalid Fields in Conditions",[12,189,190],{},"GlideRecord can log a warning and return unexpectedly broad results when a query references a field that does not exist. This is both a correctness and performance risk, particularly when field names are assembled dynamically.",[12,192,193,194,197],{},"Use ",[27,195,196],{},"isValidField()"," when a field comes from configuration or input. During development, check system logs for invalid query messages and test scripts with realistic data volumes. A typo should fail safely rather than turn a targeted update into a table-wide operation.",[19,199,201,202,205],{"id":200},"_4-use-setlimit-when-you-need-only-a-few-rows","4. Use ",[27,203,204],{},"setLimit()"," When You Need Only a Few Rows",[12,207,208],{},"If a process needs one matching record or a small batch, tell the database:",[32,210,212],{"className":34,"code":211,"language":36,"meta":37,"style":37},"var task = new GlideRecord('task');\ntask.addQuery('correlation_id', externalId);\ntask.setLimit(1);\ntask.query();\nif (task.next()) {\n  \u002F\u002F Process the match.\n}\n",[27,213,214,234,249,263,271,284,291],{"__ignoreMap":37},[41,215,216,218,221,223,225,227,229,232],{"class":43,"line":44},[41,217,48],{"class":47},[41,219,220],{"class":51}," task ",[41,222,55],{"class":47},[41,224,58],{"class":47},[41,226,62],{"class":61},[41,228,65],{"class":51},[41,230,231],{"class":68},"'task'",[41,233,72],{"class":51},[41,235,236,239,241,243,246],{"class":43,"line":75},[41,237,238],{"class":51},"task.",[41,240,81],{"class":61},[41,242,65],{"class":51},[41,244,245],{"class":68},"'correlation_id'",[41,247,248],{"class":51},", externalId);\n",[41,250,251,253,256,258,261],{"class":43,"line":98},[41,252,238],{"class":51},[41,254,255],{"class":61},"setLimit",[41,257,65],{"class":51},[41,259,260],{"class":92},"1",[41,262,72],{"class":51},[41,264,265,267,269],{"class":43,"line":113},[41,266,238],{"class":51},[41,268,149],{"class":61},[41,270,152],{"class":51},[41,272,273,275,278,281],{"class":43,"line":144},[41,274,162],{"class":47},[41,276,277],{"class":51}," (task.",[41,279,280],{"class":61},"next",[41,282,283],{"class":51},"()) {\n",[41,285,287],{"class":43,"line":286},6,[41,288,290],{"class":289},"sJ8bj","  \u002F\u002F Process the match.\n",[41,292,294],{"class":43,"line":293},7,[41,295,296],{"class":51},"}\n",[12,298,299,301,302,305],{},[27,300,204],{}," is especially useful for existence checks, duplicate detection, and scheduled jobs that intentionally process bounded batches. For deterministic batch processing, add an appropriate ",[27,303,304],{},"orderBy()"," and persist a reliable checkpoint rather than repeatedly selecting an arbitrary first set.",[19,307,309],{"id":308},"_5-use-glideaggregate-for-counts-and-totals","5. Use GlideAggregate for Counts and Totals",[12,311,312,313,316],{},"Do not retrieve thousands of records merely to increment a JavaScript counter. ",[27,314,315],{},"GlideAggregate"," performs aggregation in the database and returns a much smaller result.",[32,318,320],{"className":34,"code":319,"language":36,"meta":37,"style":37},"var count = new GlideAggregate('incident');\ncount.addQuery('active', true);\ncount.addQuery('assignment_group', groupSysId);\ncount.addAggregate('COUNT');\ncount.query();\nif (count.next()) {\n  gs.info('Active incidents: ' + count.getAggregate('COUNT'));\n}\n",[27,321,322,342,359,371,385,393,404,432],{"__ignoreMap":37},[41,323,324,326,329,331,333,336,338,340],{"class":43,"line":44},[41,325,48],{"class":47},[41,327,328],{"class":51}," count ",[41,330,55],{"class":47},[41,332,58],{"class":47},[41,334,335],{"class":61}," GlideAggregate",[41,337,65],{"class":51},[41,339,69],{"class":68},[41,341,72],{"class":51},[41,343,344,347,349,351,353,355,357],{"class":43,"line":75},[41,345,346],{"class":51},"count.",[41,348,81],{"class":61},[41,350,65],{"class":51},[41,352,86],{"class":68},[41,354,89],{"class":51},[41,356,93],{"class":92},[41,358,72],{"class":51},[41,360,361,363,365,367,369],{"class":43,"line":98},[41,362,346],{"class":51},[41,364,81],{"class":61},[41,366,65],{"class":51},[41,368,107],{"class":68},[41,370,110],{"class":51},[41,372,373,375,378,380,383],{"class":43,"line":113},[41,374,346],{"class":51},[41,376,377],{"class":61},"addAggregate",[41,379,65],{"class":51},[41,381,382],{"class":68},"'COUNT'",[41,384,72],{"class":51},[41,386,387,389,391],{"class":43,"line":144},[41,388,346],{"class":51},[41,390,149],{"class":61},[41,392,152],{"class":51},[41,394,395,397,400,402],{"class":43,"line":286},[41,396,162],{"class":47},[41,398,399],{"class":51}," (count.",[41,401,280],{"class":61},[41,403,283],{"class":51},[41,405,406,409,412,414,417,420,423,426,428,430],{"class":43,"line":293},[41,407,408],{"class":51},"  gs.",[41,410,411],{"class":61},"info",[41,413,65],{"class":51},[41,415,416],{"class":68},"'Active incidents: '",[41,418,419],{"class":47}," +",[41,421,422],{"class":51}," count.",[41,424,425],{"class":61},"getAggregate",[41,427,65],{"class":51},[41,429,382],{"class":68},[41,431,141],{"class":51},[41,433,435],{"class":43,"line":434},8,[41,436,296],{"class":51},[12,438,439,440,89,443,89,446,89,449,89,452,455],{},"Use it for ",[27,441,442],{},"COUNT",[27,444,445],{},"SUM",[27,447,448],{},"MIN",[27,450,451],{},"MAX",[27,453,454],{},"AVG",", and grouped reporting. This reduces record transfer, object creation, and server-side loop work.",[19,457,459],{"id":458},"_6-keep-queries-outside-loops","6. Keep Queries Outside Loops",[12,461,462],{},"The classic N+1 query problem occurs when a script runs another GlideRecord query for every row in its outer result. One initial query plus 1,000 inner queries creates avoidable database traffic.",[12,464,465],{},"Where possible, collect identifiers and query related data in a consolidated operation, use reference information already available, or redesign the process around a relationship table. Cache stable lookups in an object during the transaction. If each row truly requires separate work, move it to controlled asynchronous batches rather than a long interactive transaction.",[19,467,469],{"id":468},"_7-use-dot-walking-carefully","7. Use Dot-Walking Carefully",[12,471,472],{},"Dot-walked conditions are convenient, but queries across references can introduce joins and more complex execution plans. They are not inherently wrong; the risk depends on table size, selectivity, and index coverage.",[12,474,475],{},"For frequently executed logic, compare a dot-walked query with alternatives such as resolving the reference IDs first and filtering directly on the reference field. Do not denormalize data blindly, but recognize when a simple-looking condition causes expensive database work.",[19,477,479],{"id":478},"_8-avoid-unnecessary-sorting","8. Avoid Unnecessary Sorting",[12,481,482,484,485,488],{},[27,483,304],{}," and ",[27,486,487],{},"orderByDesc()"," can require the database to sort a large result set, especially when the ordering is not supported by a suitable index. Sort only when the business outcome depends on order.",[12,490,491,492,494],{},"This matters with ",[27,493,204],{},": asking for the ten most recently updated records is a legitimate ordered query, while sorting thousands of rows that will all receive the same update provides no value. Keep the selected columns, filters, order, and limit aligned with the exact task.",[19,496,498],{"id":497},"_9-keep-record-processing-lightweight","9. Keep Record Processing Lightweight",[12,500,501,502,505],{},"Query time is only part of transaction time. Within a ",[27,503,504],{},"while (gr.next())"," loop, avoid repeated logging, synchronous integrations, complex calculations, and individual updates that trigger extensive business logic.",[12,507,508,509,512,513,516],{},"Do not use ",[27,510,511],{},"setWorkflow(false)"," or ",[27,514,515],{},"autoSysFields(false)"," as generic performance switches; they change platform behavior and auditability. Use them only in controlled scenarios with documented consequences. For large corrections, process bounded batches, monitor impact, and provide a restart strategy.",[12,518,519,520,523],{},"Also avoid ",[27,521,522],{},"getRowCount()"," as the default way to count a large query. When only the count matters, use GlideAggregate.",[19,525,527],{"id":526},"_10-measure-before-and-after","10. Measure Before and After",[12,529,530],{},"Optimization should be evidence-driven. Reproduce the slow transaction in a sub-production environment with representative data, review transaction logs and slow-query diagnostics, and capture the query, row count, and duration.",[12,532,533,534,538],{},"ServiceNow administrators can use tools such as ",[535,536,537],"strong",{},"Debug SQL",", session debugging, transaction logs, and database performance views according to their access and release. Enable verbose diagnostics briefly and carefully because they can generate substantial output.",[12,540,541],{},"Look beyond one execution. A 200-millisecond query run once a day may be harmless; the same query run on every form load can be costly. Record frequency, concurrency, table growth, and user-facing impact. After changing filters or indexes, measure again and confirm the returned data is still correct.",[19,543,545],{"id":544},"final-thoughts","Final Thoughts",[12,547,548],{},"Fast GlideRecord code starts with precise data access. Apply selective conditions, use appropriate indexes, limit results, aggregate in the database, avoid queries inside loops, and remove unnecessary sorting and per-record work.",[12,550,551],{},"Most importantly, test with production-like volume and measure the complete transaction. A query optimization is successful only when it reduces resource use while preserving the business result.",[553,554,555],"style",{},"html pre.shiki code .sCydW, html code.shiki .sCydW{--shiki-default:#D73A49;--shiki-dark:#D73A49}html pre.shiki code .sKWpL, html code.shiki .sKWpL{--shiki-default:#24292E;--shiki-dark:#24292E}html pre.shiki code .se37E, html code.shiki .se37E{--shiki-default:#6F42C1;--shiki-dark:#6F42C1}html pre.shiki code .sOTlB, html code.shiki .sOTlB{--shiki-default:#032F62;--shiki-dark:#032F62}html pre.shiki code .sMN4m, html code.shiki .sMN4m{--shiki-default:#005CC5;--shiki-dark:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":37,"searchDepth":75,"depth":75,"links":557},[558,559,560,561,563,564,565,566,567,568,569],{"id":21,"depth":75,"text":22},{"id":166,"depth":75,"text":167},{"id":186,"depth":75,"text":187},{"id":200,"depth":75,"text":562},"4. Use setLimit() When You Need Only a Few Rows",{"id":308,"depth":75,"text":309},{"id":458,"depth":75,"text":459},{"id":468,"depth":75,"text":469},{"id":478,"depth":75,"text":479},{"id":497,"depth":75,"text":498},{"id":526,"depth":75,"text":527},{"id":544,"depth":75,"text":545},"2026-08-17","Improve ServiceNow GlideRecord performance with indexed filters, encoded queries, row limits, GlideAggregate, efficient loops, and practical diagnostics.",null,"md",[575,578,581,584],{"question":576,"answer":577},"How can I make a GlideRecord query faster in ServiceNow?","Filter on selective indexed fields, avoid broad queries, limit the returned rows, and retrieve only records the process needs. Validate the generated SQL and execution time with ServiceNow diagnostics before adding a custom index.",{"question":579,"answer":580},"Should I use GlideAggregate instead of GlideRecord?","Use GlideAggregate when you need a count, sum, minimum, maximum, average, or grouped result. It lets the database calculate the result instead of returning every matching row for server-side counting.",{"question":582,"answer":583},"Does the order of addQuery calls affect GlideRecord performance?","The database optimizer generally determines the execution plan, so reordering addQuery calls is not a reliable optimization. Query selectivity, suitable indexes, table size, and the final conditions matter more.",{"question":585,"answer":586},"When should I add a database index in ServiceNow?","Consider an index only for a frequent, important query that remains slow after its filters and scope are corrected. Confirm the query pattern and work with ServiceNow support or your platform owner because extra indexes increase storage and write overhead.","10 Ways to Optimize GlideRecord Queries in ServiceNow",{},true,"\u002Fblog\u002Fservicenow-gliderecord-query-performance",{"title":5,"description":571},"\u002Fimages\u002Fblog\u002Fservicenow-gliderecord-query-performance.jpg","blog\u002Fservicenow-gliderecord-query-performance","-U_hld7-ZOekyI-LQ-VHznFEaBlDTkfPRuzgAaKtJSA",1788768210459]