|
1 | | -# Performance |
| 1 | +--- |
| 2 | +description: >- |
| 3 | + We take performance seriously and performance is always on top of mind when |
| 4 | + adding new features to Umbraco uMS. |
| 5 | +--- |
2 | 6 |
|
3 | | -We take performance serious and performance is always on top of mind when adding new features to uMarketingSuite. |
| 7 | +# Performance |
4 | 8 |
|
5 | | -Within the uMarketingSuite we have implemented several performance optimizations and there are also some configuration you can do yourself to optimize the performance of your Umbraco solution with uMarketingSuite. |
| 9 | +Within the Umbraco uMS we have implemented several performance optimizations and there are also some configurations you can do yourself to optimize the performance of your Umbraco solution with uMarketingSuite. |
6 | 10 |
|
7 | | -## Seperate processes for storing, parsing and reporting |
| 11 | +## Separate processes for storing, parsing, and reporting |
8 | 12 |
|
9 | | -As documented in the [dataflow process](/the-umarketingsuite-broad-overview/dataflow-pipeline/) there are different steps for [collecting](/the-umarketingsuite-broad-overview/dataflow-pipeline/data-collection/), [storing](/the-umarketingsuite-broad-overview/dataflow-pipeline/data-storage/), [parsing](/the-umarketingsuite-broad-overview/dataflow-pipeline/data-parsing/) and [reporting](/the-umarketingsuite-broad-overview/dataflow-pipeline/reporting/) the data. This is primarily done for performance reasons. |
| 13 | +As documented in the [dataflow process](../../../../the-umarketingsuite-broad-overview/dataflow-pipeline/) there are different steps for [collecting](../../../../the-umarketingsuite-broad-overview/dataflow-pipeline/data-collection/), [storing](../../../../the-umarketingsuite-broad-overview/dataflow-pipeline/data-storage/), [parsing](../../../../the-umarketingsuite-broad-overview/dataflow-pipeline/data-parsing/), and [reporting](../../../../the-umarketingsuite-broad-overview/dataflow-pipeline/reporting/) the data. This is primarily done for performance reasons. |
10 | 14 |
|
11 | | -### Data collection |
| 15 | +The collection is done in memory of the web server (or webservers if you have multiple web servers in a load-balanced |
12 | 16 |
|
13 | | -The collection is done in memory of the webserver (or webservers if you have multiple webservers in a [loadbalanced setup](https://our.umbraco.com/Documentation/Getting-Started/Setup/Server-Setup/Load-Balancing/)). This will have some impact on the available memory on the webserver but this is probably pretty limited. You can tweak the parameters '**FlushRateInRecords**' and '**FlushIntervalInSeconds**' in the [configuration file](/installing-umarketingsuite/configuration-options-1-x/), when you want to use more or less memory. |
| 17 | +Storing causes the data to flow from the memory to the database. The memory is free again and can be used for other data. The data is stored at that moment in the raw data tables. |
14 | 18 |
|
15 | | -Storing causes the data to flow from the memory to the database. The memory is free again and can be used for other data. The data is stored at that moment in the raw datatables. |
| 19 | +In our production websites we see that the average data size per record in the table `uMarketingSuiteAnalyticsRawPageView` is 0,9 kb. This means that every visitor stores 0,9 kb of data. |
16 | 20 |
|
17 | | -In our production websites we see that the average datasize per record in the table **uMarketingSuiteAnalyticsRawPageView** is 0,9 kb. This means that every visitor stores 0,9 kb data. |
| 21 | +For the `uMarketingSuiteRawClientSideData` it depends a bit on the implementation of the clientside events. If you track a lot of [custom events](../../../../the-umarketingsuite-broad-overview/dataflow-pipeline/data-collection/) this table will probably be bigger. On average we see that this is around 0,4 kb per visitor that can execute JavaScript (all bots are excluded because of this). |
18 | 22 |
|
19 | | -For the **uMarketingSuiteRawClientSideData** it depends a bit on the implementation of the clientside events. If you track a lot of [custom events](/the-umarketingsuite-broad-overview/dataflow-pipeline/data-collection/) this table will probably be bigger. On average we see that this is around 0,4 kb per visitor that can execute JavaScript (all bots are excluded because of this). |
| 23 | +This data can be found for your database with the following SQL Statement: |
20 | 24 |
|
21 | | -This data can be found for your own database with the following SQL Statement: |
| 25 | +``` |
| 26 | +/*** |
| 27 | +Copied and applied for the raw data tables from https://support.managed.com/kb/a227/how-to-find-large-tables-in-sql-database.aspx |
| 28 | +* Find the number of rows and the size of tables |
| 29 | +***/ |
22 | 30 |
|
23 | | - /*** |
24 | | - Copied and applied for the raw datatables from https://support.managed.com/kb/a227/how-to-find-large-tables-in-sql-database.aspx |
25 | | - * Find the number of rows and the size of tables |
26 | | - ***/ |
27 | | - |
28 | | - CREATE TABLE #temp (table_name sysname ,row_count INT,reserved_size VARCHAR(50),data_size VARCHAR(50),index_size VARCHAR(50),unused_size VARCHAR(50))SET NOCOUNT ONINSERT #tempEXEC sp_msforeachtable 'sp_spaceused ''?''' |
| 31 | +CREATE TABLE #temp (table_name sysname ,row_count INT,reserved_size VARCHAR(50),data_size VARCHAR(50),index_size VARCHAR(50),unused_size VARCHAR(50))SET NOCOUNT ONINSERT #tempEXEC sp_msforeachtable 'sp_spaceused ''?''' |
29 | 32 |
|
30 | | - SELECT a.table_name,a.row_count,COUNT(*) AS col_count,a.data_sizeFROM #temp aINNER JOIN information_schema.columns bON a.table_name collate database_default = b.table_name collate database_defaultOR REPLACE(REPLACE(a.table_name, '[dbo].[',''),']','') = b.table_name collate database_defaultWHERE a.table_name LIKE 'uMarketingSuite%raw%'GROUP BY a.table_name, a.row_count, a.data_sizeORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS integer) DESC |
| 33 | +SELECT a.table_name,a.row_count,COUNT(*) AS col_count,a.data_sizeFROM #temp aINNER JOIN information_schema.columns bON a.table_name collate database_default = b.table_name collate database_defaultOR REPLACE(REPLACE(a.table_name, '[dbo].[',''),']','') = b.table_name collate database_defaultWHERE a.table_name LIKE 'uMarketingSuite%raw%'GROUP BY a.table_name, a.row_count, a.data_sizeORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS integer) DESC |
31 | 34 |
|
32 | | - DROP TABLE #temp |
| 35 | +DROP TABLE #temp |
| 36 | +``` |
33 | 37 |
|
34 | 38 | ### Data parsing |
35 | 39 |
|
36 | 40 | In the data parsing the data is fetched from the raw data tables and stored in normalized tables. At that moment the raw data could be deleted and only the normalized data tables are needed. The data parsing is the heaviest step of the total process so this is where we put most of our performance TLC in. |
37 | 41 |
|
38 | | -The data parsing process runs in a background job on the webserver. Within [the configuration file](/installing-umarketingsuite/configuration-options-1-x/) you can specify how many records are fetched to parse and how often the process needs to run. It's also possible to specify which server(s) needs to be responsible for the parsing process. |
| 42 | +The data parsing process runs in a background job on the webserver. Within [the configuration file](../../../../installing-umarketingsuite/configuration-options-1-x/) you can specify how many records are fetched to parse and how often the process needs to run. It's also possible to specify which server(s) need to be responsible for the parsing process. |
39 | 43 |
|
40 | 44 | On average we see that the amount of stored data is only 0,1 kb per visit. This is only 10% of the original amount in the raw data tables. |
41 | 45 |
|
42 | 46 | The SQL Script for determining that is: |
43 | 47 |
|
44 | | - /*** |
45 | | - * Copied and applied for the uMarketingSuite datatables from https://support.managed.com/kb/a227/how-to-find-large-tables-in-sql-database.aspx |
46 | | - * Find the number of rows and the size of tables |
47 | | - ***/ |
48 | | - |
49 | | - CREATE TABLE #temp (table_name sysname ,row_count INT,reserved_size VARCHAR(50),data_size VARCHAR(50),index_size VARCHAR(50),unused_size VARCHAR(50))SET NOCOUNT ONINSERT #tempEXEC sp_msforeachtable 'sp_spaceused ''?''' |
| 48 | +``` |
| 49 | +/*** |
| 50 | +* Copied and applied for the Umbraco uMS data tables from https://support.managed.com/kb/a227/how-to-find-large-tables-in-sql-database.aspx |
| 51 | +* Find the number of rows and the size of tables |
| 52 | +***/ |
| 53 | +
|
| 54 | +CREATE TABLE #temp (table_name sysname ,row_count INT,reserved_size VARCHAR(50),data_size VARCHAR(50),index_size VARCHAR(50),unused_size VARCHAR(50))SET NOCOUNT ONINSERT #tempEXEC sp_msforeachtable 'sp_spaceused ''?''' |
50 | 55 |
|
51 | | - SELECT SUM(a.row_count) as [total number of rows],SUM(CAST(REPLACE(a.data_size, ' KB','') as integer)) as [total data size]FROM #temp aWHERE a.table_name LIKE 'uMarketingSuiteAnalytics%' AND NOT a.table_name LIKE 'uMarketingSuiteAnalytics%raw%' |
| 56 | +SELECT SUM(a.row_count) as [total number of rows],SUM(CAST(REPLACE(a.data_size, ' KB','') as integer)) as [total data size]FROM #temp aWHERE a.table_name LIKE 'uMarketingSuiteAnalytics%' AND NOT a.table_name LIKE 'uMarketingSuiteAnalytics%raw%' |
52 | 57 |
|
53 | | - SELECT a.table_name,a.row_count,COUNT(*) AS col_count,a.data_sizeFROM #temp aINNER JOIN information_schema.columns bON a.table_name collate database_default = b.table_name collate database_defaultOR REPLACE(REPLACE(a.table_name, '[dbo].[',''),']','') = b.table_name collate database_default WHERE a.table_name LIKE 'uMarketingSuiteAnalytics%' AND NOT a.table_name LIKE 'uMarketingSuiteAnalytics%raw%' GROUP BY a.table_name, a.row_count, a.data_sizeORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS integer) DESC |
| 58 | +SELECT a.table_name,a.row_count,COUNT(*) AS col_count,a.data_sizeFROM #temp aINNER JOIN information_schema.columns bON a.table_name collate database_default = b.table_name collate database_defaultOR REPLACE(REPLACE(a.table_name, '[dbo].[',''),']','') = b.table_name collate database_default WHERE a.table_name LIKE 'uMarketingSuiteAnalytics%' AND NOT a.table_name LIKE 'uMarketingSuiteAnalytics%raw%' GROUP BY a.table_name, a.row_count, a.data_sizeORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS integer) DESC |
54 | 59 |
|
55 | | - DROP TABLE #temp |
| 60 | +DROP TABLE #temp |
| 61 | +``` |
56 | 62 |
|
57 | 63 | ## Show me more numbers |
58 | 64 |
|
59 | | -With the two SQL scripts above you can find out how much data is used by the uMarketingSuite. If you want to see how long the processing step takes you can run this script to see the processing speed for the raw pageviews: |
| 65 | +With the two SQL scripts above you can find out how much data is used by the Umbraco uMS. If you want to see how long the processing step takes you can run this script to see the processing speed for the raw pageviews: |
60 | 66 |
|
61 | | - SELECT AVG(isnull(datediff(ms, processingStarted, processingFinished),0)) |
62 | | - , CAST(processingStarted as DATE) |
63 | | - FROM [uMarketingSuiteAnalyticsRawPageView] |
64 | | - WHERE processingstarted IS NOT NULL |
65 | | - AND processingFinished IS NOT NULL |
66 | | - AND processingFailed = 0 |
67 | | - GROUP BY CAST(processingStarted as DATE) |
68 | | - ORDER BY CAST(processingStarted as DATE) |
| 67 | +``` |
| 68 | +SELECT AVG(isnull(datediff(ms, processingStarted, processingFinished),0)) |
| 69 | + , CAST(processingStarted as DATE) |
| 70 | + FROM [uMarketingSuiteAnalyticsRawPageView] |
| 71 | + WHERE processingstarted IS NOT NULL |
| 72 | + AND processingFinished IS NOT NULL |
| 73 | + AND processingFailed = 0 |
| 74 | + GROUP BY CAST(processingStarted as DATE) |
| 75 | + ORDER BY CAST(processingStarted as DATE) |
| 76 | +``` |
69 | 77 |
|
70 | 78 | and for the raw clientsidedata: |
71 | 79 |
|
72 | | - SELECT AVG(isnull(datediff(ms, processingStarted, processingFinished),0)) |
73 | | - , CAST(processingStarted as DATE) |
74 | | - FROM [uMarketingSuiteAnalyticsRawClientSideData] |
75 | | - WHERE processingstarted IS NOT NULL |
76 | | - AND processingFinished IS NOT NULL |
77 | | - AND processingFailed = 0 |
78 | | - GROUP BY CAST(processingStarted as DATE) |
79 | | - ORDER BY CAST(processingStarted as DATE) |
| 80 | +``` |
| 81 | + SELECT AVG(isnull(datediff(ms, processingStarted, processingFinished),0)) |
| 82 | + , CAST(processingStarted as DATE) |
| 83 | + FROM [uMarketingSuiteAnalyticsRawClientSideData] |
| 84 | + WHERE processingstarted IS NOT NULL |
| 85 | + AND processingFinished IS NOT NULL |
| 86 | + AND processingFailed = 0 |
| 87 | + GROUP BY CAST(processingStarted as DATE) |
| 88 | + ORDER BY CAST(processingStarted as DATE) |
| 89 | +``` |
80 | 90 |
|
81 | | -We try to keep the average parsing **speed under the 100 ms**. Please let us know if you see anything different. |
| 91 | +We try to keep the average parsing **speed under 100 ms**. Please let us know if you see anything different. |
82 | 92 |
|
83 | 93 | ## Optimized infrastructure |
84 | 94 |
|
85 | 95 | You can also optimize your server infrastructure to tweak the performance. There are a few options that you could apply: |
86 | 96 |
|
87 | | -- You could setup more webservers in [a loadbalanced setup](https://our.umbraco.com/Documentation/Getting-Started/Setup/Server-Setup/Load-Balancing/). Each of these webservers will collect data of the visitor, but you can specify in the configuration which webserver(s) is responsible for the parsing of the data. You could also setup one specific server only for parsing the data. In that case the other webservers will have almost no impact on their performance. To set this up you need to set the parameter '**IsProcessingServer**' to '**false**' in [your configuration file](/installing-umarketingsuite/settings-section/the-configuration-file/) for all servers that do not need to process the data and set it to '**true**' on the server(s) that is responsible for parsing. If there is not server with this setting set to '**true**' the raw data of the uMarketingSuite will take place, but the data will never be processed. |
88 | | -- By default the uMarketingSuite stores its data in the same database as Umbraco. It uses the default connection string of Umbraco (named '**umbracoDbDSN**'). It is possible to specify a separate database for all uMarketingSuite data. This could be another database on the same server but also another databaseserver. To do this you need to specify a new connection string in your application and give that connectionstring a name. In [the configuration file](/installing-umarketingsuite/configuration-options-1-x/) you can now specify this name in the field '**DatabaseConnectionStringName**'. |
| 97 | +* You could set up more webservers in [a load-balanced setup](https://our.umbraco.com/Documentation/Getting-Started/Setup/Server-Setup/Load-Balancing/). Each of these web servers will collect data from the visitor, but you can specify in the configuration which web server (s) is responsible for the parsing of the data. You could also set up one specific server only for parsing the data. In that case, the other web servers will have almost no impact on their performance. To set this up you need to set the parameter '`IsProcessingServer`' to '`false`' in [your configuration file](../../../../installing-umarketingsuite/settings-section/the-configuration-file/) for all servers that do not need to process the data and set it to '`true`' on the server(s) that is responsible for parsing. If there is no server with this setting set to '`true`' the raw data of the Umbraco uMS will take place, but the data will never be processed. |
| 98 | +* By default the uMarketingSuite stores its data in the same database as Umbraco. It uses the default connection string of Umbraco (named '`umbracoDbDSN`'). It is possible to specify a separate database for all uMarketingSuite data. This could be another database on the same server but also another database server. To do this you need to specify a new connection string in your application and give that connection string a name. In [the configuration file](../../../../installing-umarketingsuite/configuration-options-1-x/), you can now specify this name in the field '`DatabaseConnectionStringName`'. |
0 commit comments