我正在为媒体内容广播公司开发数据分析仪表板。即使用户单击某个频道,日志/记录也会存储到MySQL DB中。以下是存储有关频道播放时间的数据的表格。
这是表结构:
_____________________________________
| 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
答案 0 :(得分:1)
我开始在评论中写这个,因为这些是提示而不是一个明确的答案。但那太长了
首先,对WHERE
子句中出现的列进行索引是常识(但并非总是经验法则):
playing_date BETWEEN '' AND ''
AND country_code LIKE ''
AND device_report_tag LIKE ''
AND channel_report_tag LIKE ''
如果您的列具有非常高的基数(您的标记列???),那么将它们编入索引可能不是一个好主意。 <{1}}和Country_code
应编入索引。
此处的问题是您的查询中有playing_date
个问题。这个操作符是一个杀手,你在3列上使用它。这对数据库来说太糟糕了。所以问题是:真的需要吗?
例如,我认为没有明显的理由在国家/地区代码上制作 LIKE 。你真的会这样查询:
LIKE
检索英国和美国? 你可能不会。您可能知道您要搜索的国家/地区的机会很高,所以您应该这样做:
AND country_code LIKE 'U%'
如果国家/地区列已编入索引,那么速度会快得多
接下来,如果您真的想在2个标记列上生成AND country_code IN ('UK','US')
,而不是执行LIKE
,则可以尝试此操作
LIKE
也可以将标记列索引为FULLTEXT,尤其是在使用AND MATCH(device_report_tag) AGAINST ('anything*' IN BOOLEAN MODE)
进行搜索时。我用LIKE ='anything%'
搜索,索引可能不会有多大帮助。
我还可以说每天有数百万行,你可能需要对你的表进行PARTITION(比如日期)。并且关注您的数据,日期和其他内容的综合索引可能有所帮助。
真的,对于你的复杂问题,没有简单而直接的答案,特别是你所展示的内容(不是很多)。
答案 1 :(得分:1)
单独的索引不如复合索引有用。不幸的是,你有很多可能的组合,你(显然)允许使用通配符,这可能会破坏索引的效用。
建议您使用客户端代码构建WHERE
子句,而不是用&#39;&#39;
在复合索引中,最后放置一个范围。 date BETWEEN ... AND ...
是&#34;范围&#34;。
LIKE 'abc' -- same as = 'abc', so why not change to that.
LIKE 'abc%' -- is a "range"
LIKE '%abc' -- can't use an index.
IN ('CA', 'TX') -- sometimes optimizes like '=', sometimes like 'range'.
所以......观察用户要求的查询,然后构建复合索引以满足它们。一些规则:
INDEX(a,b)
由INDEX(a,b,c)
处理,因此仅包含后者。