2016-04-22 74 views
0

我们有一个表MySQL中,下面是模式MySql的多列索引如何工作

CREATE TABLE campaigns (
    domain varchar(50) , 
    campaign_id bigint(12) , 
    log_time datetime , 
    log_type int, 
    node_id bigint(12) 
) 

有关表的简要信息

一个域可以有多个广告活动和一个广告系列可以有多个节点

表具有1.5亿行。独特的域名是40k。

我想在这个表中创建一个综合指数来获得两个运动水平和节点级报告

如果我创建综合指数假设像下面

KEY campid_domain_nodeid_logtime (`campaign_id`,`domain`,`node_id`,`log_time`) 

所做的是它完全满足以下查询这意味着无论在运动水平和节点级

活动层级报告

select count(*) from campaigns 
where domain = 'aaa' and campaign_id = '1235' 
and log_time between '2016-01-01 00:00:00' and '2016-02-02 00:00:00' 

节点级别的报告

select count(*) from campaigns 
     where domain = 'aaa' and campaign_id = '1235' and node_id = '2345' and log_time between '2016-01-01 00:00:00' and '2016-02-02 00:00:00 

感谢

+0

你可以通过这个链接: http://stackoverflow.com/questions/1823685/when-should-i-use-a-composite-index –

+1

是的,该索引将由两个查询使用,假设数据分布允许它。只要你有AND条件和相等性,索引列的顺序就是重要的.Corrections(假设WHERE条件与索引列一样多,所以第一个条件不能完全利用索引 – Mihai

+0

我已经小提琴它:http://sqlfiddle.com/#!9/2bade9/1 它似乎使用这两个索引我管理它有点意外 – sab

回答

0

否,综合指数是不会帮助任何你在这个格式列出的2个查询。 where标准中的字段需要与索引中的顺序相同。

我也将由log_time移动到第三的位置更改索引中字段的顺序:

KEY campid_domain_nodeid_logtime (`campaign_id`,`domain`,`log_time`,`node_id`) 

1查询更改CAMPAIGN_ID和域的顺序:

select count(*) from campaigns 
where campaign_id = '1235' and domain = 'aaa' 
and log_time between '2016-01-01 00:00:00' and '2016-02-02 00:00:00' 

第二查询更改campaign_id和domain + node_id和log_time的顺序:

select count(*) from campaigns 
where campaign_id = '1235' and domain = 'aaa' 
    and log_time between '2016-01-01 00:00:00' and '2016-02-02 00:00:00' 
    and node_id = '2345' 

您可以运行解释来验证索引的使用。如果您有任何与节点相关的查询(不会在log_time上进行过滤),那么这些查询只能使用索引的campaign_id和域部分。

+0

where语句中的查询子子句的顺序应该无关紧要,你应该说“A和B”或“B和A”,并且数据库的查询分析器只会看到字段A和B是需要的,并将检查wha t indix可用。 – Meier

0

https://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html

上面的链接中多列索引说太多关于索引的顺序

在创建列索引以下顺序

域,CAMPAIGN_ID,NODEID,登录时间

并将节点报告更改为

select count(*) from campaigns 
where domain = 'aaa' and campaign_id = '1235' 
and log_time between '2016-01-01 00:00:00' and '2016-02-02 00:00:00' 
and node_id = '2345' 
+0

查询语句中的顺序应该不重要,因为sql是声明式的,并且查询优化器应根据需要对其重新排序。问题是另一个查询,其中节点字段丢失,但它位于索引的中间。 – Meier

4

您可以将索引视为快速查找的订单清单。如果你有一个区段A,B,C,d一个复合索引,该名单将被排序,然后与B,比C也是同样的。行,除D

A1 | B1 | C1 | D1 | -> pointer to row 
A1 | B1 | C1 | D2 | -> pointer to row 
A1 | B1 | C2 | D1 | -> pointer to row 
A1 | B1 | C2 | D2 | -> pointer to row 
A1 | B2 | C1 | D1 | -> pointer to row 
... 
A2 | B1 | C1 | D1 | -> pointer to row 
A2 | B1 | C1 | D2 | -> pointer to row 

查询优化会检查你的查询。 如果您的查询要求A,B,C,D,一切都很好。查询的顺序对于一个好的数据库应该不重要,因此您也可以编写查询where D and C and B and A

如果您的查询只询问A,再次一切正常,因为具有相同A的所有行都是一个接一个。

如果您的查询仅针对D,索引是没用的。具有相同D但不同A的行分布在整个列表中。

如果您的查询要求A,B,D,就像您的广告系列级报告一样,那么该索引有一定的用处。它可以用来加速A和B的查找,但是它需要迭代所有数据,因为C丢失了。

您可以定义多个索引。缺点是每个额外的索引都会使写入速度变慢,并且在硬盘上需要一些空间。