此DB表的最佳索引是什么?

时间:2017-07-18 11:17:58

标签: mysql indexing

我有一个用于存储统计数据的表。目前,这一行在一天结束时填充了大约1000万行,然后复制到每日统计表并删除。出于这个原因,我无法使用自动递增的主键。

这是表结构:

CREATE TABLE `stats` (
`shop_id` int(11) NOT NULL,
`title` varchar(255) CHARACTER SET latin1 NOT NULL,
`created` datetime NOT NULL,
`mobile` tinyint(1) NOT NULL DEFAULT '0',
`click` tinyint(1) NOT NULL DEFAULT '0',
`conversion` tinyint(1) NOT NULL DEFAULT '0',
`ip` varchar(20) CHARACTER SET latin1 NOT NULL,
KEY `shop_id` (`shop_id`,`created`,`ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

我在shop_id, created, ip上有一个密钥,但我不确定应该使用哪些列来创建最佳索引以进一步提高查找速度?

下面的查询在没有密钥的情况下大约需要12秒,使用上面的索引大约需要1.5秒:

SELECT DATE(CONVERT_TZ(`created`, 'UTC', 'Australia/Brisbane')) AS `date`, COUNT(*) AS `views`
FROM `stats`
WHERE `created` <= '2017-07-18 09:59:59'
AND `shop_id` = '17515021'
AND `click` != 1
AND `conversion` != 1
GROUP BY DATE(CONVERT_TZ(`created`, 'UTC', 'Australia/Brisbane'))
ORDER BY DATE(CONVERT_TZ(`created`, 'UTC', 'Australia/Brisbane'));

2 个答案:

答案 0 :(得分:1)

  • 如果没有保证唯一的列(或列组合),那么 do 会有AUTO_INCREMENT id。不要担心截断/删除。 (但是,如果ID未重置,您可能需要使用BIGINT,而不是INT UNSIGNED以避免溢出。)
  • 请勿使用id作为主键,而是使用PRIMARY KEY(shop_id, created, id), INDEX(id)
  • 非传统的PK将以两种方式帮助提高表现,同时保持独特性(由于id的加法)。 INDEX(id)旨在让AUTO_INCREMENT满意。 (每小时或每天DELETE是一个单独的问题。)
  • 根据每小时(或分钟)构建摘要表。它将包含这样的计数 - 400K /小时或7K /分钟。每小时(或分钟)增加一次,这样你就不必在一天结束时完成所有的工作。
  • 摘要表还可以过滤点击和/或转化。 如果你需要的话,它可以保留两者。
  • 如果点击/转化只有两种状态(0&amp; 1),请不要说!= 1,说= 0;优化器在=处比在!=处好得多。
  • 如果他们处于2状态并且您更改为=,那么这变得可行且更好:INDEX(shop_id, click, conversion, created) - created必须是最后一个。
  • 在汇总表汇总时,不要打扰TZ;稍后应用转换。
  • 更好的是,不要使用DATETIME,使用TIMESTAMP以便您不需要转换(假设您正确设置了TZ)。

毕竟,如果你还有问题,请重新开始讨论;可能会有进一步的调整。

答案 1 :(得分:-1)

在你的where子句中,首先使用列,它将返回一小组结果,依此类推,并以相同的顺序创建索引。
你有 WHERE created <= '2017-07-18 09:59:59' AND shop_id = '17515021' AND click != 1 AND conversion != 1

如果创建将返回少量的set作为与其他3列的比较,那么你很好,否则你在where子句中的第一个位置的那个列然后根据相同的解释选择第二列并根据你创建索引where子句。
如果你认为订单没问题,那就创建一个索引

KEY created_shopid_click_conversion (created,shop_id, click, conversion);