【问题标题】:Best Indexing technique for a table that does SELECT WHERE on different columns对不同列执行 SELECT WHERE 的表的最佳索引技术
【发布时间】:2020-12-06 02:17:26
【问题描述】:

我希望为我的日志表实现高效的索引技术,如下所示:

MariaDB [Webapp]> explain logs;
+----------------+--------------+------+-----+---------+----------------+
| Field          | Type         | Null | Key | Default | Extra          |
+----------------+--------------+------+-----+---------+----------------+
| id             | int(11)      | NO   | PRI | NULL    | auto_increment |
| user_id        | int(11)      | YES  | MUL | NULL    |                |
| activity_name  | varchar(20)  | NO   |     | NULL    |                |
| activity_key   | varchar(255) | NO   |     | NULL    |                |
| activity_value | varchar(255) | NO   |     | NULL    |                |
| activity_date  | datetime     | NO   | MUL | NULL    |                |
+----------------+--------------+------+-----+---------+----------------+

我是这样搜索的:

SELECT *
FROM logs
WHERE user_id IN (1, 3)
  AND activity_name IN ('login', 'logout')
  AND activity_date >= '2020-02-01'
  AND activity_date <= '2020-06-01'

涉及列user_idactivity_nameactivity_date


有时像这样:

SELECT *
FROM logs
WHERE user_id IN (1, 3)
  AND activity_name IN ('login', 'logout')

user_idactivity_name 都涉及但没有日期。


也像这样:
SELECT *
FROM logs
WHERE user_id IN (1, 3)
  AND activity_date >= '2020-02-01'
  AND activity_date <= '2020-06-01'

SELECT *
FROM logs
WHERE activity_name IN ('login', 'logout')
  AND activity_date >= '2020-02-01'
  AND activity_date <= '2020-06-01'

我确实读过复合索引,如果我的搜索是有序的,它们会很好,但正如你所见,它不是,所以我认为它不合适..

我还读到 single index 一次只能用于一列,所以我认为这对我的情况不利..

请有任何想法,我对 MySQL 不太熟悉。如何优化查询?

注意:我不使用通配符 (*),因为我阅读它会减慢速度,但我只是为了缩短查询以便于理解而使用它 p>

【问题讨论】:

    标签: mysql indexing mariadb query-optimization where-clause


    【解决方案1】:

    对于每个查询,基本想法是有一个索引,其列覆盖where 子句。对于您的这无法使用四个查询的单个索引来实现 - 我认为您需要 3 个索引。

    首先,考虑以下索引:

    logs(user_id, activity_name, activity_date)
    

    它匹配第一个查询的where 子句:

    WHERE 
        user_id IN (1, 3) 
        AND activity_name IN ('login', 'logout') 
        AND activity_date >= '2020-02-01' 
        AND activity_date <= '2020-06-01'
    

    还有第二个查询(这里忽略第三个索引列):

    WHERE 
        user_id IN (1, 3) 
        AND activity_name IN ('login', 'logout') 
    

    对于其他两个查询,您需要两个单独的索引:

    WHERE 
        user_id IN (1, 3) 
        AND activity_date >= '2020-02-01' 
        AND activity_date <= '2020-06-01'
    

    需求:

    logs(user_id, activity_date)
    

    还有:

    WHERE 
        activity_name IN ('login', 'logout') 
        AND activity_date >= '2020-02-01' 
        AND activity_date <= '2020-06-01'
    

    需求:

    logs(activity_name, activity_date)
    

    旁注:一般情况下,不要盲目select *;相反,在结果集中枚举您想要的列 - 特别是如果您不想要它们全部。如果您只需要两三列,请考虑将它们添加到索引的末尾,从而将其转换为 覆盖 索引。

    【讨论】:

    • 另外请记住,在范围条件中使用的第一列之后,索引的后续列不用于搜索或排序。最好的希望是index condition pushdown,这比没有索引的帮助要好,但不如索引过滤。
    猜你喜欢
    • 1970-01-01
    • 2019-08-28
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 2015-07-24
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多