How to Query for licensed users when have over 900 active licenses
Asked by mary.moore:

I asked this on someone else's question: <https://community.atlassian.com/t5/Confluence-questions/How-to-query-active-users-in-Confluence/qaq-p/24532?_ga=2.208006866.1942474880.1528220541-1332829241.1528220541> but never got a response, so I'm re-asking it as it's own question now.

When we were under 500 users the below macro worked perfectly for me; however, now that we are over 900 users - the system times out. Is there a better way to get all Confluence users name and last login for audit purposes?

```
## Macro title: Last Login## Macro has a body: N## Body processing: Selected body processing option## Output: Selected output option#### Developed by: Andrew Frayling## Date created: 11/02/2012## Installed by: <your name>## Macro to display the last login date of users who have access to the current space## @noparams#set($containerManagerClass = $content.class.forName('com.atlassian.spring.container.ContainerManager'))#set($getInstanceMethod = $containerManagerClass.getDeclaredMethod('getInstance',null))#set($containerManager = $getInstanceMethod.invoke(null,null))#set($containerContext = $containerManager.containerContext)#set($loginManager = $containerContext.getComponent('loginManager'))#set($users = $userAccessor.getUsers())<table class="confluenceTable">  <tr>    <th class="confluenceTh">User</th>    <th class="confluenceTh">Last Successful Login</th>  </tr>#foreach($user in $users)  ## list the last login date of users who can view the current space      <tr>      <td class="confluenceTd">#usernameLink($user.name)</td>    #if (!$loginManager.getLoginInfo($user).lastSuccessfulLoginDate)      <td class="confluenceTd" style="background-color:#ff0000"><strong>NEVER</strong></td>    #else      <td class="confluenceTd">$action.dateFormatter.formatDateTime($loginManager.getLoginInfo($user).lastSuccessfulLoginDate)</td>    #end    </tr>  #end</table>
```


Answers:
author: Sven Schatter _Lively Apps_
body: Hi [@mary.moore](/t5/user/viewprofilepage/user-id/1477997),

it looks like you've reached the limit of what can be reasonably achieved with User Macros. You might be able to find some short-term workarounds but sooner or later you'll hit the same or similar problems as this solution obviously doesn't scale.

A better approach would be to directly query the Confluence database for this kind of data. There's an [official Atlassian article](https://confluence.atlassian.com/confkb/how-to-identify-inactive-users-in-confluence-214335880.html) that presents some example Queries for this. Using SQL queries you are so much more flexible and it's much more performant.

To get the exact same data that your User Macro currently generates you could use this SQL:

```
SELECT cu.user_name,
       li.successdate
FROM cwd_user cu
JOIN user_mapping um ON um.username = cu.user_name
LEFT JOIN logininfo li ON li.username = um.user_key
ORDER BY li.successdate;
```

If you want to display your data in Confluence you could simply use [PocketQuery](https://marketplace.atlassian.com/apps/1211199/pocketquery-for-confluence) to do so. With a few modifications to the standard PocketQuery template you can even get the same representation as from your User Macro:

![temp.png](https://community.atlassian.com/t5/image/serverpage/image-id/77806i5ED2A5ED42943F6D/image-dimensions/598x334?v=v2 "temp.png")

This is the PocketQuery Template code I've used:

```
<table class="aui confluenceTable pocketquery-table">
  <thead>
    <tr>
      <th class="confluenceTh">User</th>
      <th class="confluenceTh">Last Successful Login</th>
    </tr>
  </thead>

  <tbody>
    #foreach ($user in $result)
      <tr>
        <td class="confluenceTd">#usernameLink($user.user_name)</td>
        #if($user.successdate)
          <td class="confluenceTd">$dateFormatter.formatDateTime($user.successdate)</td>
        #else
          <td class="confluenceTd" style="background-color:#ff0000"><strong>NEVER</strong></td>
        #end
      </tr>
    #end
  </tbody>
</table>
```

So what's the difference between row 2 (PocketQuery) and 3 (User Macro) in the image now?

* PocketQuery uses a SQL query which is a lot faster.
* SQL is much more flexible so once you reach 100.000 users and run into performance problems again you could easily add a line like "**WHERE successdate \< xxx** " or "**LIMIT 1000**" to the statement.
* PocketQuery has a macro option that is called "load dynamically" so even if you run into performance problems this allows you to decouple the querying process from the macro rendering / page rendering process. The page will render normally (no timeout!) and PocketQuery will execute your query in the background. Once the result is ready PocketQuery will insert it into the page. This will even work if the query took an incredible amount of time like 10 minutes or more. But that probably shouldn't even happen.

I hope this helps! :)

Best regards,  
Sven


Tags: confluence-server

server