2015-05-28 114 views
0

模式是这样的visits_table是否可以优化这些查询?

+---------------------------+----------------------+------+-----+---------+----------------+ 
| Field      | Type     | Null | Key | Default | Extra   | 
+---------------------------+----------------------+------+-----+---------+----------------+ 
| idvisit     | int(10) unsigned  | NO | PRI | NULL | auto_increment | 
| idsite     | int(10) unsigned  | NO | MUL | NULL |    | 
| idvisitor     | binary(8)   | NO |  | NULL |    | 
| visit_time    | datetime    | NO |  | NULL |    | 
| user_id     | varchar(200)   | YES |  | NULL |    | 
| config_cookie    | tinyint(1)   | NO |  | NULL |    | 
| custom_var_k1    | varchar(200)   | YES |  | NULL |    | 
| custom_var_v1    | varchar(200)   | YES |  | NULL |    | 
+---------------------------+----------------------+------+-----+---------+----------------+ 

索引:

+----------------------+------------+------------------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table    | Non_unique | Key_name      | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+----------------------+------------+------------------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| visits_table   |   0 | PRIMARY      |   1 | idvisit    | A   |  1502 | NULL  | NULL |  | BTREE  |   |    | 
| visits_table   |   1 | index_idsite_datetime  |   1 | idsite     | A   |   5 | NULL  | NULL |  | BTREE  |   |    | 
| visits_table   |   1 | index_idsite_datetime  |   2 | visit_time    | A   |  1502 | NULL  | NULL |  | BTREE  |   |    | 
| visits_table   |   1 | index_idsite_idvisitor  |   1 | idsite     | A   |   1 | NULL  | NULL |  | BTREE  |   |    | 
| visits_table   |   1 | index_idsite_idvisitor  |   2 | idvisitor    | A   |   500 | NULL  | NULL |  | BTREE  |   |    | 
+----------------------+------------+------------------------------+--------------+------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 

,我已经准备了两个查询:

SELECT 
    COUNT(`idvisit`) AS `visits_count`, 
    DATE(`visit_time`) AS `date` 
FROM (
    SELECT * 
    FROM 
     `visits_table` 
    WHERE 
     `idsite` = 2 
     AND `visit_time` >= '2015-04-01 00:00:00' 
     AND `visit_time` <= '2015-04-30 23:59:59' 
) AS `visits` 
WHERE 1 
GROUP BY 
    DATE(`visit_time`); 



+----+-------------+----------------------+------+----------------------------------------------+------+---------+------+------+---------------------------------+ 
| id | select_type | table    | type | possible_keys        | key | key_len | ref | rows | Extra       | 
+----+-------------+----------------------+------+----------------------------------------------+------+---------+------+------+---------------------------------+ 
| 1 | PRIMARY  | <derived2>   | ALL | NULL           | NULL | NULL | NULL | 1469 | Using temporary; Using filesort | 
| 2 | DERIVED  | visits_table   | ALL | index_idsite_datetime,index_idsite_idvisitor | NULL | NULL | NULL | 1502 | Using where      | 
+----+-------------+----------------------+------+----------------------------------------------+------+---------+------+------+---------------------------------+ 
在MySQL 5.6

行2型= ref时,键= index_idsite_datetime,key_len = 4,ref = const,Extra =使用索引

SELECT 
     COUNT(`idvisit`) AS `visits_count`, 
     DATE(`visit_time`) AS `date` 
    FROM 
     `visits_table` 
    WHERE 
     `idsite` = 2 
     AND `visit_time` >= '2015-04-01 00:00:00' 
     AND `visit_time` <= '2015-04-30 23:59:59' 
    GROUP BY 
     DATE(`visit_time`); 

+----+-------------+----------------------+-------+----------------------------------------------+-----------------------+---------+------+------+-----------------------------------------------------------+ 
| id | select_type | table    | type | possible_keys        | key     | key_len | ref | rows | Extra              | 
+----+-------------+----------------------+-------+----------------------------------------------+-----------------------+---------+------+------+-----------------------------------------------------------+ 
| 1 | SIMPLE  | visits_table   | range | index_idsite_datetime,index_idsite_idvisitor | index_idsite_datetime | 12  | NULL | 1468 | Using where; Using index; Using temporary; Using filesort | 
+----+-------------+----------------------+-------+----------------------------------------------+-----------------------+---------+------+------+-----------------------------------------------------------+ 

我有86M行的表和两个查询需要约2小时执行。有什么我可以做的,以加快这些查询?

+0

我认为问题是强制MYSQL排序结果(filesort)的GROUP BY DATE(...)。如果您可以将Visit_time分隔为Visit_Date和Visit_Time,则您的查询速度会更快。你有多少内存和多少符合条件的结果(在分组之前)? – Tim3880

+0

尝试运行['ANALYZE TABLE VISITS_TABLE'](https://dev.mysql.com/doc/refman/5.0/en/analyze-table.html),然后重试第二个查询。此外,将语法更改为'AND visit_time BETWEEN'2015-04-01 00:00:00'AND'2015-04-30 23:59:59'' – Bohemian

回答

1

我建议编写查询作为:

SELECT COUNT(*) AS `visits_count`, 
     DATE(`visit_time`) AS `date` 
FROM `visits_table` 
WHERE `idsite` = 2 AND 
     `visit_time` >= '2015-04-01' AND 
     `visit_time` < '2015-05-01' 
GROUP BY DATE(`visit_time`); 

这可能节省大量的时间丝毫,因为指数现在是一个覆盖索引。

我认为改善查询的一种方法是摆脱group by。尝试这样的查询:

select dte, 
     (select count(*) 
     from visits_table 
     where idsite = 2 and 
       visit_time >= dates.dte AND visit_time < dates.dte + interval 1 day 
from (select date('2015-04-01') as dte union all 
     select date('2015-04-02') as dte 
    ) dates; 

MySQL是如何使用索引相关子查询远胜它是关于使用索引聚集。这种方法的缺点是时间会随着结果集中天数的增加而线性增加。

+0

您是否意味着工会每天都像日复一日?像这样select?(select date('2015-04-01')as dte union all select date('2015-04-02')as dte(...)union all select date('2015-04-30 “))。所以我会结合所有的日子?这将是29个工会会不会很慢? –

+0

@ SebastianPiskorski。 。 。是。我只是从两天开始。做30个常量记录的联合基本上没有时间在查询的上下文中。问题是相关的子查询,您可以在更短的时间内进行测试。 –