本页介绍了CockroachDB v2.0.6版本中新发现的限制,以及早期版本中发现的未解决的问题。

新的限制

对默认复制区域(default replication zone)的变更不会应用于现有的复制区域(replication zones)

.default 集群范围内的replication zone的更改不会自动应用于现有replication zone,包括重要内部数据的replication zone。为使整个群集保持可用,存放内部数据的“system ranges”必须始终保持其半数以上副本可用。因此,如果增加默认复制因子(replication factor),请务必同时增加重要内部数据的复制因子

DECIMAL类型数值校验失效

在以下条件下,CockroachDB收到的值将与客户端发送的值不同,可能导致不正确的值被插入到数据库中,或从数据库中读取到不正确的数据,而且不会有错误提示:

1.Query使用占位符(例如,$1)的方式将值传递给服务器。 2.传递DECIMAL类型的值。 3.使用二进制格式编码十进制值。

大多数客户端驱动程序和框架使用文本格式来传递占位符值,因此不受此限制的影响。 目前已知Elixir的Ecto框架会受此影响,其他框架也可能受到影响。 如果有疑惑,可以使用SQL语句日志记录来控制CockroachDB如何从客户端接收十进制值。

单个语句的update和write的限制

单个语句最多可以执行64MiB的组合的更新。 当语句超出这些限制时,其事务将中止。 目前,INSERT INTO ... SELECT FROMCREATE TABLE AS SELECT查询可能会遇到这些限制。

要放宽这些限制,可以修改群集设置:kv.raft.command.max_size,但是,修改此设置可能会增加群集中节点对内存的使用。 对于INSERT INTO .. SELECT FROM语句,另一种解决方法是把要插入的数据拆分成多个事务。

在v1.1版本中,该限制是针对整个事务(即所有语句所做的更改的总和),并且限制了更新的数量和大小。 在此版本中,只限制大小,且独立应用于每个语句。 注意,即使事务不再受到直接的限制,大型事务也会对集群产生性能影响。

Import导致大量磁盘争用

IMPORT有时会因“context canceled”错误而失败,或者多次重启,最后无法完成任务。 如果发生这种情况,可能是由于发生了激烈的磁盘竞争,这可以通过将集群设置kv.bulk_io_write.max_rate 设置为低于最大磁盘写入速度的值来缓解。 例如,要将其设置为10MB/s,请执行:

> SET CLUSTER SETTING kv.bulk_io_write.max_rate = '10MB';

INSERT ... ON CONFLICT检查约束

已经在v2.0.4解决,查看#26699

CHECK约束未对INSERT ... ON CONFLICT语句产生的更新值生效。 请看以下示例:

> CREATE TABLE ab (a INT PRIMARY KEY, b INT, CHECK (b < 1));

一个简单的INSERT语句由于未通过Check约束而执行失败,因为它应该:

> INSERT INTO ab (a,b) VALUES (1, 12312);
pq: failed to satisfy CHECK constraint (b < 1)

但是,使用INSERT ... ON CONFLICT的相同语句却能执行成功,并导致数据违反约束:

> INSERT INTO ab (a, b) VALUES (1,0); -- create some initial valid value
> INSERT INTO ab (a, b) VALUES (1,0) ON CONFLICT (a) DO UPDATE SET b = 123132;
> SELECT * FROM ab;
+---+--------+
| a |   b    |
+---+--------+
| 1 | 123132 |
+---+--------+
(1 row)

多次通过name引用CTE(通用table表达式)

目前无法通过名称多次引用CTE表达式

例如,以下查询无效,因为CTEa被引用两次:

WITH a AS (VALUES (1), (2), (3))
  SELECT * FROM a, a;

将CTE与数据修改语句一起使用

如果顶层查询未直接或间接引用包含数据修改语句的CTE表达式,则不会执行数据修改语句。

例如,以下查询不插入任何行,因为未使用CTE a

WITH a AS (INSERT INTO t(x) VALUES (1), (2), (3))
  SELECT * FROM b;

此外,即使使用CTE a,以下查询也不会插入任何数据行,因为使用a的其他CTE本身未使用:

WITH a AS (INSERT INTO t(x) VALUES (1), (2), (3)),
       b AS (SELECT * FROM a)
  SELECT * FROM c;

要确定是否有效进行修改,请使用EXPLAIN并检查所需的数据修改是否是整个最终查询计划的一部分。

使用带有视图的CTE

在用于定义视图的selection查询中,尚不可能使用CTE表达式。

使用带有VALUES子句的CTE

在VALUES子句内的子查询中,还不可能在VALUES子句外部使用CTE表达式,例如:

WITH a AS (...) VALUES ((SELECT * FROM a));

将CTE与Set Operations一起使用

现在还不可能在set运算符的右操作数中,使用在set表达式之外定义的CTE表达式,例如:

WITH a AS (SELECT 1)
  SELECT * FROM users UNION SELECT * FROM a; -- "a" used on the right, not yet supported.

对于UNION,您可以通过交换操作数来解决此限制。 对于其他集合运算符,您可以在右侧操作数内部定义CTE表达式。

为Node Map分配纬度/经度

如果区域中某个组成部分在其他区域具有相同的名字的组成部分,将无法将纬度/经度坐标分配给该部分。 例如:

Node Region Datacenter
Node1 us-east datacenter-1
Node2 us-west datacenter-1

在这种情况下,如果尝试为如上两个Datacenter设置纬度/经度坐标,您将收到“primary key exists”错误,并且无法显示Node Map。此时可通过为Region设置纬度/经度坐标解决。

PARTITION BY中的占位符

在表创建或表更改期间定义表分区时,无法在PARTITION BY子句中使用占位符。

添加具有某些DEFAULT值的列

当列使用Sequence、计算列或某些计算表达式作为DEFAULT值时,目前无法向表中添加该列,例如:

> ALTER TABLE add_default ADD g INT DEFAULT nextval('initial_seq')
> ALTER TABLE add_default ADD g OID DEFAULT 'foo'::regclass::oid
> ALTER TABLE add_default ADD g INT DEFAULT 'foo'::regtype::INT

未解决的限制

管理界面中的可用容量指标

如果您在一台计算机上运行多个节点(不建议在生产中使用),并且没有使用--store为每个节点指定分配的最大存储容量,管理界面中的容量指标将不正确。 这是因为当在一台机器上运行多个节点时,机器的硬盘被视为每个节点的可用存储,而实际上,所有节点都共用同一个硬盘。在计算总可用容量时,会将它作为硬盘大小乘以机器上的节点数,从而使容量指标错误。

事务中的schema变更

在单个事务中:

在prepared语句执行过程中发生schema变更

在prepared语句执行完成前,它涉及的表发生schema变更,CockroachDB允许prepared语句根据已变更的表schema来返回结果,例如:

> CREATE TABLE users (id INT PRIMARY KEY);
> PREPARE prep1 AS SELECT * FROM users;
> ALTER TABLE users ADD COLUMN name STRING;
> INSERT INTO users VALUES (1, 'Max Roach');
> EXECUTE prep1;
+----+-----------+
| id |   name    |
+----+-----------+
|  1 | Max Roach |
+----+-----------+
(1 row)

因此,建议不要在prepared语句或其他类似的情况下使用SELECT *

在prepared语句执行完之前,当正在写入的表的schema发生变更时,prepared中的INSERTUPSERTDELETE语句会出现不一致。

INSERT ON CONFLICTVSUPSERT

当插入/更新表的所有列,并且表没有二级索引时,我们建议使用UPSERT语句而不是等效的INSERT ON CONFLICT语句。 INSERT ON CONFLICT总是执行读取以确定必要的写入,而UPSERT语句可在不读取的情况下写入,使其更快。

当使用两列的简单SQL表来模拟直接KV访问时,此问题尤其重要。 在这种情况下,请务必使用UPSERT语句。

使用\\|在SQL shell中执行大输入

在内置SQL shell中,使用\\|运算符从文件中执行大量输入可能导致服务器关闭连接。 这是因为\\|将整个文件作为单个查询发送到服务器,这可能超过服务器可以从任何客户端接受的数据包大小的上限(16MB)。

作为一种解决方法,使用cat data.sql | cockroach sql而不是交互式shell。

ALTER TABLE ADD COLUMN期间由DEFAULT表达式生成的新值

使用DEFAULT表达式执行ALTER TABLE ADD COLUMN语句时,会生成新值:

在延迟不均衡的部署环境中重新平衡Load-based租约

当使用--locality启动节点时,CockroachDB会尝试在最靠近请求源的节点上放置副本租约持有者(客户端请求转发到的副本)。 这意味着当客户端请求在地理位置上移动时,也是如此选择副本租赁持有者。

但是,在以下情况下,您可能会看到由于在数据中心之间高频率转移租约导致的高延迟:

要检测是否发生这种情况,请打开Admin UI,选择 Queues 仪表板,将鼠标悬停在 Replication Queue 图表上,然后检查 Leases Transferred / second 数据点。 如果该值始终大于0,则应考虑使用其他位置层停止并重新启动每个节点,以改善请求延迟的问题。

例如,假设从数据中心A中的节点到数据中心B中的节点的延迟为10毫秒,但是从数据中心A中的节点到数据中心C中的节点的延迟为100毫秒。为了确保在租约持有者的重新平衡中会考虑到A和B的距离相对更近的因素,您可以重新启动 数据中心A和B中具有相同region的节点,--locality = region = foo,datacenter = a--locality = region = foo,datacenter = b,同时在数据中心C中重新启动具有不同区域的节点 ,--locality = region = bar,datacenter = c

Overload resolution for collated strings

Many string operations are not properly overloaded for collated strings, 例如:

> SELECT 'string1' || 'string2';
+------------------------+
| 'string1' || 'string2' |
+------------------------+
| string1string2         |
+------------------------+
(1 row)
> SELECT ('string1' collate en) || ('string2' collate en);
pq: unsupported binary operator: <collatedstring{en}> || <collatedstring{en}>

单列族的最大大小

创建或更新行时,如果单个列族中所有值的组合大小超过表的最大range大小(默认为64MiB),则操作可能会失败,或者群集性能可能会大幅下降。

作为解决方法,您可以手动将表的列拆分为多个列族,或者使用更高的最大range大小的来创建特定于表的区域配置。

在单个节点上同时进行客户端连接和运行查询

当节点同时具有大量客户端连接和运行查询时,节点可能会因内存耗尽而崩溃。 这是因为CockroachDB没有根据节点上的可用RAM量准确地限制客户端和查询的数量。

为防止内存耗尽,请监控每个节点的内存使用情况,并确保最大CockroachDB内存使用量与可用系统RAM之间有一定的差距。 有关CockroachDB中内存使用的更多详细信息,请参阅 this blog post.

SQL子表达式和内存使用情况

许多SQL子表达式(例如,ORDER BYUNION /INTERSECT /EXCEPTGROUP BY,子查询)在处理查询的节点上的RAM中累积中间结果。 如果操作尝试处理的行数多于可容纳在RAM中的行数,则该节点将崩溃或报告内存容量错误。 有关CockroachDB中内存使用的更多详细信息, 查看 this blog post.

OR表达式的查询计划

给定一个类似SELECT * FROM foo WHERE a> 1 OR b> 2的查询,即使有适当的索引同时满足a> 1b> 2,查询规划器也会执行完整的表或索引扫描 因为它不能同时使用这两个条件。

DELETEUPDATE的权限

每个DELETEUPDATE语句构造一个SELECT语句,即使没有涉及WHERE子句也是如此。 结果,执行DELETEUPDATE的用户需要表的DELETESELECTUPDATESELECT权限。

cockroach dump不支持循环外键引用

cockroach dump命令将成功为具有外键引用的表创建dump文件,或者具有循环外键依赖性的一组表(例如,a依赖b,b依赖a)。 但是,该dump文件只能在手动从CREATE TABLE语句中删除外键定义,并在INSERT语句之后将它们添加为ALTER TABLE ... ADD CONSTRAINT语句之后才能执行。