【问题标题】:Optimize SELECT MySql query using INDEXING使用 INDEXING 优化 SELECT MySql 查询
【发布时间】:2017-01-24 13:09:13
【问题描述】:

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

【问题讨论】:

  • 您必须对列进行索引,首先更改表结构,在“应用,还原”按钮之前,有一个选项卡部分,您必须在其中选择“索引”选项卡,在此选项卡中选择要索引的列,然后应用它
  • @chiragpatel “如何应用索引”,我知道。我要问的是在我提到的查询中应用哪些列。感谢任何方式的关注。
  • 索引适用于处于 where 条件的列,如果该列数据类型为 Integer,则它执行得很快。
  • 您可以为您的like-code 添加示例值吗?如果您使用like '%xxx%'(所以前面的%),索引不会加快速度。所以你可能会在playing_date 上留下一个索引,也许是playing_date, channel_report_tag
  • 为什么“喜欢”?!?!?!?国家代码怎么可能是 LIKE ?!?!

标签: mysql performance optimization indexing


【解决方案1】:

单独的索引不如复合索引有用。不幸的是,您有许多可能的组合,并且(显然)允许使用通配符,这可能会破坏索引的实用性。

建议您使用客户端代码来构建WHERE 子句,而不是用''填充它

在复合索引中,将一个范围放在最后。 date BETWEEN ... AND ... 是一个“范围”。

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) 处理,因此只包含后者。
  • 不要有超过十几个索引。

Index Cookbook

【讨论】:

  • 如果我使用这个查询,将 LIKE 替换为 = 运算符。请看看我的问题编辑。
  • 为清楚起见,如果您知道这是您想要的,请使用=。没有通配符 =LIKE 的表现非常相似。如果最终用户可以提供通配符,那么简单地使用LIKE 并让优化器意识到它可以改进它是合理的。
【解决方案2】:

我开始在评论中写这个,因为这些是提示而不是明确的答案。但是太长了

首先,对出现在WHERE 子句中的列进行索引是常识(但并不总是经验法则):

   playing_date BETWEEN '' AND ''
    AND country_code LIKE ''        
    AND device_report_tag LIKE '' 
    AND channel_report_tag LIKE  ''

如果您的列具有非常高的基数(您的标签列???),那么为它们编制索引可能不是一个好主意。 Country_codeplaying_date 应该被索引。

这里的问题是您的查询中有太多LIKE。这个运算符是一个杀手,你在 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%' 搜索,索引可能没有多大帮助。

我还可以声明,每天有数百万行,您可能必须对表进行分区(例如在日期)。根据您的数据,日期和其他内容的综合索引可能会有所帮助。

真的,对于您的复杂问题,没有简单直接的答案,尤其是您展示的内容(不是很多)。

【讨论】:

  • 这些是提示,但非常有用,谢谢。基本上使用 LIKE 的原因是因为 country_code、device_report_tag 和 channel_report_tag 由用户输入的仪表板参数控制。但是你关于国家代码的观点是真实的,我可以在那里使用 IN 而不是 LIKE。
猜你喜欢
  • 2021-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 2014-07-31
相关资源
最近更新 更多