5
I have the following tables:
Each tuple of the table Pageviews (main) contains a single page view. If by chance the same person in the same session (Sessions) view the same page (Pages), a new tuple is not added in Pageviews. Instead the field is incremented Pageviews..
In one of the reports, I need the amount of unique visitors (COUNT DISTINCT Visitors id.) and pageviews (SUM Pageviews.) at a particular time (day, week, month and year) of a specific store (of which the Stores.code).
The appointments I’m making at the moment are:
Visitors
SELECT DISTINCT Visitors.id
FROM PageViews
INNER JOIN VisitorsStores ON VisitorsStores.id = PageViews.visitor
INNER JOIN Stores ON Stores.id = VisitorsStores.store
INNER JOIN Sessions ON Sessions.id = VisitorsStores.session
INNER JOIN Visitors ON Visitors.id = Sessions.visitor
WHERE
DATE(PageViews.createdAt) BETWEEN '2017-11-01' AND '2017-11-30' AND
Stores.code = 'loja1';
Pageviews
SELECT SUM(quantity) AS qtde
FROM PageViews
INNER JOIN VisitorsStores ON VisitorsStores.id = PageViews.visitor
INNER JOIN Stores ON Stores.id = VisitorsStores.store
WHERE
DATE(PageViews.createdAt) BETWEEN '2017-11-01' AND '2017-11-30' AND
Stores.code = 'loja1';
Both
SET @loja := 'loja1';
SET @inicio := '2017-11-01';
SET @fim := '2017-11-31';
SELECT
COUNT(tVisitors.qtdVisitors) AS visitors,
SUM(tVisitors.qtdPageViews) as pageViews
FROM (
SELECT
Visitors.id AS qtdVisitors,
SUM(quantity) AS qtdPageViews
FROM PageViews
INNER JOIN VisitorsStores ON VisitorsStores.id = PageViews.visitor
INNER JOIN Stores ON Stores.id = VisitorsStores.store
INNER JOIN Sessions ON Sessions.id = VisitorsStores.session
INNER JOIN Visitors ON Visitors.id = Sessions.visitor
WHERE
DATE(PageViews.createdAt) BETWEEN @inicio AND @fim AND Stores.code = @loja
GROUP BY qtdVisitors
) as tVisitors;
It works great when a store has few daily access. But when a store has many accesses (some around 300 visitors and 5,000 pageviews) the consultation takes a long time to complete (32s was the longest in the mentioned situation. Stores with less than 1,000 pageviews usually take less than 3s).
The question is: How else could I make this query to be faster?
EXPLAIN query Both for a single day (05/12)
(Visitor: 696 | pageviews: 5809 | query runtime: 32s)
[
{
"id": 1,
"select_type": "PRIMARY",
"table": "<derived2>",
"type": "ALL",
"possible_keys": null,
"key": null,
"key_len": null,
"ref": null,
"rows": 6192,
"Extra": ""
},
{
"id": 1,
"select_type": "PRIMARY",
"table": "<derived3>",
"type": "ALL",
"possible_keys": null,
"key": null,
"key_len": null,
"ref": null,
"rows": 6192,
"Extra": ""
},
{
"id": 3,
"select_type": "DERIVED",
"table": "Stores",
"type": "index",
"possible_keys": "PRIMARY",
"key": "code",
"key_len": "62",
"ref": null,
"rows": 1,
"Extra": "Using where; Using index"
},
{
"id": 3,
"select_type": "DERIVED",
"table": "VisitorsStores",
"type": "ref",
"possible_keys": "PRIMARY,FK_VisitorsStores_Stores",
"key": "FK_VisitorsStores_Stores",
"key_len": "5",
"ref": "tmw_views.Stores.id",
"rows": 6192,
"Extra": "Using index"
},
{
"id": 3,
"select_type": "DERIVED",
"table": "PageViews",
"type": "ref",
"possible_keys": "FK_PageViews_VisitorsStores",
"key": "FK_PageViews_VisitorsStores",
"key_len": "8",
"ref": "tmw_views.VisitorsStores.id",
"rows": 1,
"Extra": "Using where"
},
{
"id": 2,
"select_type": "DERIVED",
"table": "Stores",
"type": "index",
"possible_keys": "PRIMARY",
"key": "code",
"key_len": "62",
"ref": null,
"rows": 1,
"Extra": "Using where; Using index; Using temporary"
},
{
"id": 2,
"select_type": "DERIVED",
"table": "VisitorsStores",
"type": "ref",
"possible_keys": "PRIMARY,FK_VisitorsStores_Sessions,FK_VisitorsStores_Stores",
"key": "FK_VisitorsStores_Stores",
"key_len": "5",
"ref": "tmw_views.Stores.id",
"rows": 6192,
"Extra": "Using where"
},
{
"id": 2,
"select_type": "DERIVED",
"table": "Sessions",
"type": "eq_ref",
"possible_keys": "PRIMARY,FK_Sessions_Visitors",
"key": "PRIMARY",
"key_len": "8",
"ref": "tmw_views.VisitorsStores.session",
"rows": 1,
"Extra": ""
},
{
"id": 2,
"select_type": "DERIVED",
"table": "Visitors",
"type": "eq_ref",
"possible_keys": "PRIMARY",
"key": "PRIMARY",
"key_len": "8",
"ref": "tmw_views.Sessions.visitor",
"rows": 1,
"Extra": "Using index"
},
{
"id": 2,
"select_type": "DERIVED",
"table": "PageViews",
"type": "ref",
"possible_keys": "FK_PageViews_VisitorsStores",
"key": "FK_PageViews_VisitorsStores",
"key_len": "8",
"ref": "tmw_views.VisitorsStores.id",
"rows": 1,
"Extra": "Using where; Distinct"
}
]
SHOW TABLE STATUS FROM tmw_views
;
{
"table": "TABLES",
"rows":
[
{
"Name": "PageViews",
"Engine": "InnoDB",
"Version": 10,
"Row_format": "Compact",
"Rows": 1560181,
"Avg_row_length": 84,
"Data_length": 131694592,
"Max_data_length": 0,
"Index_length": 194314240,
"Data_free": 12582912,
"Auto_increment": null,
"Create_time": "2017-10-27 23:31:14",
"Update_time": null,
"Check_time": null,
"Collation": "utf8_general_ci",
"Checksum": null,
"Create_options": "",
"Comment": ""
},
{
"Name": "PageViewsYear",
"Engine": "InnoDB",
"Version": 10,
"Row_format": "Compact",
"Rows": 25,
"Avg_row_length": 655,
"Data_length": 16384,
"Max_data_length": 0,
"Index_length": 32768,
"Data_free": 0,
"Auto_increment": 62,
"Create_time": "2017-11-27 11:17:44",
"Update_time": null,
"Check_time": null,
"Collation": "utf8_general_ci",
"Checksum": null,
"Create_options": "",
"Comment": ""
},
{
"Name": "Pages",
"Engine": "InnoDB",
"Version": 10,
"Row_format": "Compact",
"Rows": 94648,
"Avg_row_length": 116,
"Data_length": 11026432,
"Max_data_length": 0,
"Index_length": 0,
"Data_free": 4194304,
"Auto_increment": 205925,
"Create_time": "2017-10-27 23:31:14",
"Update_time": null,
"Check_time": null,
"Collation": "utf8_general_ci",
"Checksum": null,
"Create_options": "",
"Comment": ""
},
{
"Name": "Sessions",
"Engine": "InnoDB",
"Version": 10,
"Row_format": "Compact",
"Rows": 366180,
"Avg_row_length": 73,
"Data_length": 26804224,
"Max_data_length": 0,
"Index_length": 41058304,
"Data_free": 3145728,
"Auto_increment": 531262,
"Create_time": "2017-10-27 23:31:14",
"Update_time": null,
"Check_time": null,
"Collation": "utf8_general_ci",
"Checksum": null,
"Create_options": "",
"Comment": ""
},
{
"Name": "Stores",
"Engine": "InnoDB",
"Version": 10,
"Row_format": "Compact",
"Rows": 0,
"Avg_row_length": 0,
"Data_length": 16384,
"Max_data_length": 0,
"Index_length": 16384,
"Data_free": 0,
"Auto_increment": 31,
"Create_time": "2017-10-27 23:31:14",
"Update_time": null,
"Check_time": null,
"Collation": "utf8_general_ci",
"Checksum": null,
"Create_options": "",
"Comment": ""
},
{
"Name": "SystemLogs",
"Engine": "InnoDB",
"Version": 10,
"Row_format": "Compact",
"Rows": 5913,
"Avg_row_length": 1687,
"Data_length": 9977856,
"Max_data_length": 0,
"Index_length": 540672,
"Data_free": 4194304,
"Auto_increment": null,
"Create_time": "2017-11-20 15:21:31",
"Update_time": null,
"Check_time": null,
"Collation": "utf8_general_ci",
"Checksum": null,
"Create_options": "",
"Comment": ""
},
{
"Name": "Visitors",
"Engine": "InnoDB",
"Version": 10,
"Row_format": "Compact",
"Rows": 31067,
"Avg_row_length": 51,
"Data_length": 1589248,
"Max_data_length": 0,
"Index_length": 1589248,
"Data_free": 4194304,
"Auto_increment": 102579,
"Create_time": "2017-10-27 23:31:14",
"Update_time": null,
"Check_time": null,
"Collation": "utf8_general_ci",
"Checksum": null,
"Create_options": "",
"Comment": ""
},
{
"Name": "VisitorsStores",
"Engine": "InnoDB",
"Version": 10,
"Row_format": "Compact",
"Rows": 297216,
"Avg_row_length": 44,
"Data_length": 13107200,
"Max_data_length": 0,
"Index_length": 17842176,
"Data_free": 4194304,
"Auto_increment": 562767,
"Create_time": "2017-10-27 23:31:14",
"Update_time": null,
"Check_time": null,
"Collation": "utf8_general_ci",
"Checksum": null,
"Create_options": "",
"Comment": ""
}
]
}
SHOW VARIABLES LIKE 'query_cache%';
query_cache_limit 1048576
query_cache_min_res_unit 4096
query_cache_size 33554432
query_cache_strip_comments OFF
query_cache_type ON
query_cache_wlock_invalidate OFF
can post the result of EXPLAIN statement of the query Both? And if possible put also the SHOW TABLE STATUS FROM `<db_name>`; Thus, we have how to know which are the engines of the tables.
– pss1suporte
@pss1support Added requested information
– Szag-Ot
Thanks for putting it in JSON format! It makes it much easier!
– pss1suporte
Hello Szag, did you come to create some index to try to optimize these queries? How are you using Innodb the Fks implicitly create indexes. That said, indexes like
CREATE INDEX pv_createdAt_idx ON PageViews(createdAt) USING BTREE;
should help with the consultation (in return they makeinserts
a little slower). I assume thatStores.code
is also unique key or is using a single correct index?– Anthony Accioly
Yes, the fields used in the query are all indexed
– Szag-Ot
Is there a lot of time difference between the two individual queries and the unified query (using Subqueries)? For this store that takes 32 seconds, how long each of the individual queries takes?
– Anthony Accioly
Yes. Separately, the first (visitors) took 18s and the second (pageviews) 17s. That is, unified they already have a better performance.
– Szag-Ot
Um... if the individual queries are taking around half the time I remain suspicious of indexes. Especially as you are using a function
DATE(PageViews.createdAt)
depending on how you created the index Mysql will not be able to use, you could post the command you used to create the contents needed for the query?– Anthony Accioly
OK, I will fry here another solution! I will delete the above comments.
– pss1suporte
I got a solution with slightly better performance, I will post above (19s in total, against the 32s of the previous method).
– Szag-Ot
Szag-Ot, no, no .... but gave in the same!! His words above: "the first (visitors) took 18s and the second (pageviews) 17s.". Something else! You can answer your own question!
– pss1suporte
Here, in practice only reduced a query, but not optimized the query yes. That already has the cost of 17 or 18s! Understood?
– pss1suporte
You can inform the output: SHOW VARIABLES LIKE ?query_cache%';?
– pss1suporte
@pss1support Adding what was requested in the post
– Szag-Ot