Activities data model and storage
Activity tables (formerly entities) such as email, phone call, and appointment are stored in the Microsoft Dataverse database with a more sophisticated data model compared to standard tables, which are usually stored in one database table. This article will help you understand the activities data model and its impact on storage capacity. For more details regarding how activities are used, see Activity tables.
Activities underlying database tables
Activity rows are saved in the Dataverse database across multiple underlying tables. Each activity table stores corresponding rows of data in a base table (ActivityPointerBase) and an extension table that is dedicated for each specific activity type (EmailBase, TaskBase, AppointmentBase, etc.).
This table is the base table for each activity in the system. The creation of any activity such as an email, phone call, appointment, or custom activity will create a corresponding row in this table. Because this table contains one row for every activity, it is expected this table may have many rows.
This table includes all default activity columns such as subject, description, owner, regarding, status, and many more. For a full list of the columns in this table, see activitypointer EntityType. Because each of these columns are included in this base activity table and there is one row for every activity, this is often one of the largest consumers of data capacity. The description column is the same column used to store the email body for an email activity. Because an email body can include a lot of text, large emails can contribute to the growth in data capacity consumed by this table.
When you access a view such as My Activities or All Activities, the data is retrieved from the ActivityPointerBase table allowing you to see a single view of activities across multiple activity types.
Any activity in the system is retrievable using the specific activity schema name, and is also retrievable using the activitypointer schema, this functionality is useful when retrieving multiple activities of different activity types.
This table contains the party information for each activity. Each activity party represents a person or group associated with an activity. Example: Assume you created an Appointment activity which has one organizer, one owner, two required attendees, one optional attendee, and one regarding object. There would be six corresponding rows stored in this table. Another example of activity parties are all the people on an email activity on the From, To, and Cc lines.
This table contains the data to relate an attachment to an activity row.
More information: activitymimeattachment EntityType
EmailSearchBase (internal use)
This table is used for email address resolution. It is for internal use only and contains rows for each email address in the system associated to an email address formatted column.
EmailHashBase (internal use)
This table is used for smart matching and contains hashes generated for each email message in the system.
Difference between schema and storage
There is a difference between the schema exposed for individual activity tables and the underlying storage. Example: If you refer to the email entity schema accessible from SDK, all the table columns will be available and will be surfaced from different underlying tables (base table, extension table, activityparty table). However, most of these columns are stored in the base table (ActivityPointerBase), and only custom columns, if any, will be stored in the EmailBase table.
Why does ActivityPointerBase have so many rows?
Please refer to the base table definition above for more details. There is one row for each activity in the system.
Why is ActivityPointerBase consuming so much storage?
One potential cause is having many rows which contributes to the overall table size. Another potential cause is the length of text in the description column. This is the same description column used for any activity such as the body of an email activity or the description of an appointment activity.
How can I reduce ActivityPointerBase table usage?
ActivityPointerBase contains data which was saved as users create activity rows such as emails, phone calls, tasks, and appointments. As users create more activities, the table will grow. The table contains data saved by users and does not contain any internal use data. You can reduce the space used for this table by deleting any old activities which are no longer needed.
Why does ActivityPartyBase have so many rows?
There is one row for each activity participation. It’s easy to have many rows in this table, however the space utilized by these individual rows is minimal.
Why does an activity extension table consume a lot of storage?
An extension table extends the base activity table (ActivityPointerBase) for a specific activity table such as Task and is used for storing the data for any custom columns. The Task table stores data for the default attributes inside the ActivityPointerBase table in the database. If you add custom attributes to the Task table, they will be saved in the TaskBase table in the database. An extension table will have rows only when there is a custom attribute defined for the specific activity. There could be cases where a text field which contains a lot of text is defined as custom activity attribute and could cause high storage usage. Please review the custom attributes defined and the content.
Where is the body (description) of an email stored?
The email body is stored in the description column of the ActivityPointerBase table. This attribute is retrievable from both schemas: email and activitypointerbase. However, the data isn't duplicated. It is just surfaced in two locations as needed.
Submit and view feedback for