【问题标题】:mysql database composite key issuesmysql数据库复合键问题
【发布时间】:2019-04-13 05:07:28
【问题描述】:

我们有一个数据库,其中的数据表定义如下:

CREATE TABLE data
(
msts BIGINT,
variable_id INT,
p_id INT,
value DOUBLE,
PRIMARY KEY(msts,variable_id,p_id)
);

ALTER TABLE data
ADD    FOREIGN KEY (p_id)
REFERENCES p(id);

ALTER TABLE data
ADD    FOREIGN KEY (variable_id)
REFERENCES variables(id);

这个表可以包含数十亿条记录。

进行简单查询时:

SELECT COUNT(msts) from data FORCE INDEX(PRIMARY) where (
msts<1535886000000000000 AND msts>1535796060000000000  AND  
variable_id=107  AND p_id=661 );

屈服:

+-------------+
| COUNT(msts) |
+-------------+
|       89873 |
+-------------+
1 row in set (42.51 sec)

计算 89873 需要 42.51 秒。

为什么要花这么长时间才能看到主键应该充当复合索引?

这是解释:

EXPLAIN SELECT COUNT(msts) from data FORCE INDEX(PRIMARY) where 
( msts<1535886000000000000 AND msts>1535796060000000000  AND 
variable_id=107  AND plant_id=661 );

给出:

rows = 190996998
filtered=0
ref=NULL
type=range

任何帮助将不胜感激!

【问题讨论】:

  • 提示:范围扫描
  • 感谢 Lukasz 有机会在代码中描述它应该如何完成。再次感谢。

标签: mysql sql indexing database-indexes


【解决方案1】:

您的查询已被重写以更改 where 子句的顺序,是这样的。

SELECT COUNT(msts) 
  from data 
 where variable_id=107 
   and p_id=661
   and msts>1535796060000000000
   and msts<1535886000000000000;

它包含两个相等匹配,在 variable_id 和 p_id 上。然后它在 msts 上包含一个范围过滤器。因此,您需要在(variable_id, p_id, msts) 列上按该顺序 建立索引,以帮助快速满足您的查询。

为什么?您可以将 MySQL 索引视为按顺序排序的。为了满足您的查询,MySQL 随机访问第一个符合条件的项目的索引。然后它按顺序扫描它,直到最后一个项目。这称为索引范围扫描。

您的预先存在的索引首先列出 msts。这意味着您的索引无法按顺序扫描,因为索引中的每个 msts 值都可能具有其他两列的许多值。

专业提示 1: 尽可能使用COUNT(*),而不是COUNT(column)。第二个比较慢,因为它必须忽略任何为 NULL 的列值。第一个只是将它们全部计算在内。

专业提示 2:额外的单列索引没有用处,除非它们有助于加快特定查询。

专业提示 3: 强制使用索引几乎总是一个糟糕的选择。

专业提示 4: 阅读https://use-the-index-luke.com/

编辑:您询问了如何进行转换。

如果您的表还没有包含数百万行,只需像这样更改主键定义。

ALTER TABLE data 
       DROP PRIMARY KEY, 
       ADD PRIMARY KEY (variable_id, p_id, msts);

如果它确实已经包含数十亿行,您可能应该创建一个具有正确定义的新表,将现有表复制到该表中。然后复制你的数据。然后将旧表重命名为data_old什么的,将新表重命名为data。这可能是一项涉及批量数据的复杂任务;如果您无法弄清楚,请再问一个问题。

【讨论】:

  • 谢谢 O.琼斯。那么这是否涉及将主键中的顺序更改为:(variable_id,p_id,msts)?我试试看!非常感谢!
  • @kitt91 - 计划 A 重新排列 PK.. 计划 B 添加具有这 3 列的二级索引。在 10 亿行上,两者都非常耗时。 'B' 会消耗大量额外的磁盘空间。另一个index cookbook
  • @O.Jones - 谢谢这工作!速度显着提高到几分之一秒!再次感谢
猜你喜欢
  • 1970-01-01
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多