MySql如何处理复合索引

时间:2016-04-20 10:32:11

标签: mysql indexing

CREATE TABLE campaigns (
  domain varchar(50) DEFAULT NULL,
  campaign_id varchar(50) DEFAULT NULL,
  node_id varchar(50) DEFAULT NULL,
  subscriber_id varchar(50) DEFAULT NULL,
  message varchar(21000) DEFAULT NULL,
  log_time datetime DEFAULT NULL,
  log_type varchar(50) DEFAULT NULL,
  campaign_name varchar(500) DEFAULT NULL

  KEY `campid_domain_logtype_logtime_subid_index` (`campaign_id`,`domain`,`log_type`,`log_time`,`subscriber_id`),
  KEY `domain_logtype_logtime_index` (`domain`,`log_type`,`log_time`)

)

以上是MySql中我们表的模式。一个广告系列可以有多个节点。

索引campid_domain_logtype_logtime_subid_index适用于w.r.t特定广告系列的报告。

最近我们将node_id添加到此表中,现在我们需要报告w.r.t特定节点。

所以现在我计划更改我们的覆盖索引,如下所示,以支持广告系列级和节点级报告

campid_nodeid_domain_logtype_logtime_subid_index

针对特定广告系列的报告的示例查询

SELECT log_type,
        count(DISTINCT subscriber_id) AS count,
        count(subscriber_id) AS total 
FROM stats.campaign_logs USE INDEX(campid_domain_logtype_logtime_subid_index) 
where domain = 'aaa' AND campaign_id='12345' AND 
  log_type in ('EMAIL_SENT','EMAIL_OPENED','EMAIL_CLICKED')
  AND log_time BETWEEN CONVERT_TZ('2016-03-13 00:00:00','+01:30','+00:00') AND CONVERT_TZ('2016-04-13 23:59:59','+01:30','+00:00') 
GROUP BY log_type;

针对特定广告系列的特定节点ID的报告的示例查询

SELECT 
   log_type,
   count(DISTINCT subscriber_id) AS count,
   count(subscriber_id) AS total 
FROM stats.campaign_logs USE INDEX(campid_domain_logtype_logtime_subid_index) 
where domain='aaa' AND campaign_id='12345' AND 
      node_id = '56789' and 
      log_type in ('EMAIL_SENT','EMAIL_OPENED','EMAIL_CLICKED') 
      AND log_time BETWEEN CONVERT_TZ('2016-03-13 00:00:00','+01:30','+00:00') AND CONVERT_TZ('2016-04-13 23:59:59','+01:30','+00:00') 
GROUP BY log_type;

所以我的问题是这个新索引能否有效地满足我们的两种查询,如果没有请建议合适的索引。

更新

表格中的数据分发

1个域可以有多个广告系列,例如20

1 Campaign可以有多个节点,例如10

1 Campaign可以有多种日志类型,例如50

1广告系列可以拥有大量订阅者,例如100,000

1 Campaign可以有很多日志时间,因为我们在存储日志时使用mysql now()。

更新

由于

2 个答案:

答案 0 :(得分:0)

根据您的疑问,您应该创建以下索引

KEY `campid_domain_logtype_logtime_subid_index` (
    `campaign_id`, 
    `domain`, 
    `log_time`, 
    `node_id`, 
    `subscriber_id`
);
始终使用

campaign_idlog_timenode_id仅在某些情况下使用domain

不确定是否应该离开subscriber_idlog_type

在查询中看不到所有这些内容。

Campaign id, Log time, Node ID (subscriber_id ?) 也值得商榷。我不相信它具有良好的选择性,只是浪费空间。

<强>更新

根据我们在评论中的通讯

  • 广告系列ID是主列
  • 域名是第二个。尝试玩,也许你应该删除它
  • 范围选择的记录时间
  • 特定查询的节点ID

如果您经常在查询中使用subscriber_id - 请添加它。

我会删除log_type。

作为选项,尝试创建以下索引:

{
    "Header": {
        "CutQuantity": 0,
        "ETAQuantity": 0,
        "IDRPrice": 229000,
        "MasterId": 65639,
        "Name": "VENICE SATIN DBY 21491 COL 25894",
        "POQuantity": 0,
        "ProductCode": "GG01054-14B",
        "QtyOnHand": 332.1,
        "ReservedQuantity": "332.1",
        "SellingPrice": 229000,
        "TotalAvlQuantity": 0,
        "USDPrice": 26
    },
    "Batches": [{
        "AvailableQty": 25.8,
        "BatchNo": "A001",
        "BinId": 128430,
        "BinName": "Dummy-700",
        "DeptId": 23,
        "DeptName": "G.700",
        "MaxBodyId": 128430,
        "ProductCode": "GG01054-14B",
        "ProductCodeBatch": "GG01054-14B-A001",
        "ProductId": 65639,
        "ProductName": "VENICE SATIN DBY 21491 COL 25894"
    }, {
        "AvailableQty": 40,
        "BatchNo": "A002",
        "BinId": 128433,
        "BinName": "Dummy-700",
        "DeptId": 23,
        "DeptName": "G.700",
        "MaxBodyId": 128433,
        "ProductCode": "GG01054-14B",
        "ProductCodeBatch": "GG01054-14B-A002",
        "ProductId": 65639,
        "ProductName": "VENICE SATIN DBY 21491 COL 25894"
    }]
}

答案 1 :(得分:0)

构建最佳索引的基本规则:

  1. 以任何顺序包含带有'='的列;
  2. 包括另一列,最好是范围。
  3. 所以第一个查询需要INDEX(domain, campaign_id, log_time)log_type挡路了;不包括它。

    (已添加)“新”查询需要INDEX(campaign_id, node_id, domain, log_time)

    在这两种情况下,log_time都应该是最后的;其他列可以按任何顺序排列。重新排列订单可能有助于其他查询。没有一个索引对于两个查询都是最佳的。

    然后,不要使用USE INDEX;它可能会适得其反。

    More cookbook tips

    更好的解决方案更复杂:构建和维护经常需要的各种计数器/总和的汇总表。 (也许使用30分钟的时间范围。)警告:COUNT(DISTINCT ...)无法在汇总表中处理。

    为什么这些ID VARCHAR(50)而不是INT UNSIGNED?您还可以从domain等其他字段规范化中受益。 log_type可以是1字节ENUM

    您真的需要所有列都可以为空吗?

    这些列的任何组合都是唯一的吗? InnoDB真的很喜欢PRIMARY KEY