使用INDEXING优化SELECT MySql查询

时间:2016-09-16 10:27:00

标签: mysql performance optimization indexing

我正在为媒体内容广播公司开发数据分析仪表板。即使用户单击某个频道,日志/记录也会存储到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

2 个答案:

答案 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'.

所以......观察用户要求的查询,然后构建复合索引以满足它们。一些规则:

  • 最多只有一个范围,并把它放在最后。
  • Put&#39; =&#39;第一列。
  • INDEX(a,b)INDEX(a,b,c)处理,因此仅包含后者。
  • 不要超过十几个索引。

Index Cookbook