我正在为一家媒体内容广播公司开发数据分析仪表板。即使用户点击某个 channel ,日志/记录也会存储到 MySQL DB 中。以下是存储有关 channel 播放时间的数据的表格。
这是表结构:
_____________________________________
| ID INT(11) |
_____________________________________
| Channel_ID INT(11) |
_____________________________________
| playing_date (DATE) |
_____________________________________
| country_code VARCHAR(50) |
_____________________________________
| playtime_in_sec INT(11) |
_____________________________________
| count_more_then_30_min_play INT(11) |
_____________________________________
| count_15_30_min_play INT(11) |
_____________________________________
| count_0_15_min_play |
_____________________________________
| channel_report_tag VARCHAR(50) |
_____________________________________
| device_report_tag VARCHAR(50) |
_____________________________________
| genre_report_tag VARCHAR(50) |
_____________________________________
我在仪表板图表构建之一后面运行的查询是:
SELECT
channel_report_tag,
SUM(count_more_then_30_min_play) AS '>30 minutes',
SUM(count_15_30_min_play) AS '15-30 Minutes',
SUM(count_0_15_min_play) AS '0-15 Minutes'
FROM
channel_play_times_cleaned
WHERE
playing_date BETWEEN '' AND ''
AND country_code LIKE ''
AND device_report_tag LIKE ''
AND channel_report_tag LIKE ''
GROUP BY
channel_report_tag
LIMIT 10
这个查询基本上需要花费大量时间来返回结果集(假设表数据每天超过一百万条记录,并且每秒都在增加)。我遇到了这个堆栈溢出问题:What generic techniques can be applied to optimize SQL queries?其中基本上提到了使用索引作为优化 SQL 查询的技术之一。目前我很困惑如何应用索引(即在哪些列上)以优化上述查询。如果有人可以根据我的具体情况提供创建索引的帮助,我将不胜感激。对于像我这样的初学者来说,任何其他专家的意见都是值得欢迎的。
编辑:
根据@Thomas G 的建议,
我尝试改进我的查询并使其更加具体:
SELECT
channel_report_tag,
SUM(count_more_then_30_min_play) AS '>30 minutes',
SUM(count_15_30_min_play) AS '15-30 Minutes',
SUM(count_0_15_min_play) AS '0-15 Minutes'
FROM
channel_play_times_cleaned
WHERE
playing_date BETWEEN '' AND ''
AND country_code = 'US'
AND device_report_tag = 'j8'
AND channel_report_tag = 'NAT GEO'
GROUP BY
channel_report_tag
LIMIT 10
最佳答案
我开始在评论中写下这些,因为这些只是提示,而不是明确的答案。但这太长了
首先,对 WHERE
子句中出现的列建立索引是常识(但并不总是经验法则):
playing_date BETWEEN '' AND ''
AND country_code LIKE ''
AND device_report_tag LIKE ''
AND channel_report_tag LIKE ''
如果您的列具有非常高的基数(您的标签列???),那么为它们建立索引可能不是一个好主意。 Country_code
和 playing_date
应建立索引。
这里的问题是您的查询中有太多 LIKE
。这个操作符是一个 killer ,你在 3 列上使用它。这对数据库来说太糟糕了。所以问题是:真的需要吗?
例如,我认为没有明显的理由对国家/地区代码进行LIKE。你真的会这样查询吗:
AND country_code LIKE 'U%'
检索英国和美国? 你可能不会。您很可能知道您正在搜索的国家/地区,因此您应该这样做:
AND country_code IN ('UK','US')
如果对国家/地区列建立索引,速度会快很多
接下来,如果您确实想在 2 个标签列上进行 LIKE
,而不是进行 LIKE
,您可以尝试此操作
AND MATCH(device_report_tag) AGAINST ('anything*' IN BOOLEAN MODE)
还可以将标签列索引为 FULLTEXT,特别是当您使用 LIKE ='anything%'
进行搜索时。如果您使用 LIKE='%anything%'
进行搜索,索引可能不会有太大帮助。
我还可以指出,每天有数百万行,您可能必须对表进行分区(例如在日期上)。根据您的数据,日期的复合索引和其他内容可能会有所帮助。
确实,对于您的复杂问题,没有简单直接的答案,尤其是您所展示的内容(不是很多)。
关于mysql - 使用 INDEXING 优化 SELECT MySql 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39529205/