索引(index)
在数据库中,用户可以对表创建索引,以此来加速查询。RisingWave 中的索引基本与传统数据库中的索引一样,是为了加速随机查询。用户可以在表与物化视图上构建索引。
创建索引语法:
CREATE INDEX index_name ON object_name ( index_column [ ASC | DESC ], [, ...] )
[ INCLUDE ( include_column [, ...] ) ]
[ DISTRIBUTED BY ( distributed_column [, ...] ) ];
代码示例
假定我们有一张客户表和一张订单表,表结构定义如下
CREATE TABLE customers (
c_custkey INTEGER,
c_name VARCHAR,
c_address VARCHAR,
c_nationkey INTEGER,
c_phone VARCHAR,
c_acctbal NUMERIC,
c_mktsegment VARCHAR,
c_comment VARCHAR,
PRIMARY KEY (c_custkey)
);
CREATE TABLE orders (
o_orderkey BIGINT,
o_custkey INTEGER,
o_orderstatus VARCHAR,
o_totalprice NUMERIC,
o_orderdate DATE,
o_orderpriority VARCHAR,
o_clerk VARCHAR,
o_shippriority INTEGER,
o_comment VARCHAR,
PRIMARY KEY (o_orderkey)
);
如果我们希望通过用户的手机号来查询用户订单,我们可以通过在c_phone
列上建立索引来加速查询。
CREATE INDEX idx_c_phone on customers(c_phone);
SELECT * FROM customers where c_phone = '123456789';
SELECT * FROM customers where c_phone in ('123456789', '987654321');
亦或者我们希望通过手机号查询某个用户的所有订单,我们可以在 orders表的 o_custkey 列上建立索引加速join查询。
CREATE INDEX idx_o_custkey ON orders(o_custkey);
SELECT * FROM customers JOIN orders ON c_custkey = o_custkey
WHERE c_phone = '123456789';
此外RisingWave还支持更复杂的表达式索引,可以方便地使用在Json列或其他包含表达式的场景上,例如:
CREATE INDEX people_names ON people ((first_name || ' ' || last_name));
SELECT * FROM people WHERE (first_name || ' ' || last_name) = 'John Smith';
如何选择INCLUDE列
默认情况下,如果您省略 INCLUDE 子句,RisingWave 会创建一个包含表或物化视图所有列的索引,这与标准的 PostgreSQL 有所不同。为什么呢?RisingWave 作为云原生流数据库,与 PostgreSQL 有几个不同的关键之处,包括使用对象存储进行更具成本效益的存储,以及希望对于那些不熟悉数据库系统的用户创建索引尽可能简单。通过包含所有列,RisingWave 确保索引将覆盖查询所涉及的所有列,并消除了需要在主表中进行回表查询的需要。然而,对于希望自己控制include列的用户,RisingWave 仍然提供了使用 INCLUDE 子句仅包含特定列的选项。
例如:
如果您的查询只涉及某些列,您可以创建一个仅包含这些列的索引。RisingWave 优化器将自动为您的查询选择适当的索引。
-- 创建只包含特定列的索引
CREATE INDEX idx_c_phone1 ON customers(c_phone) INCLUDE (c_name, c_address);
-- RisingWave会自动选择idx_c_phone1索引如果只有特定列在SQL中被使用了
SELECT c_name, c_address FROM customers WHERE c_phone = '123456789';
如何选择DISTRIBUTED列
如果您省略 DISTRIBUTED BY 子句,RisingWave将默认使用第一个索引列作为分布式列。RisingWave将数据分布在多个节点上,并使用分布式列来确定基于索引如何分布数据。之所以使用索引的第一列作为Distributed列是为了满足前缀查询的需求。但如果默认的第一列Cardinality比较小,这有可能会造成数据不均匀,因此您可以选择指定特定的前缀作为DISTRIBUTED列
-- 创建带有指定前缀的DISTRIBUTED列索引
CREATE INDEX idx_c_phone2 ON customers(c_name, c_nationkey) DISTRIBUTED BY (c_name);
SELECT * FROM customers WHERE c_name = 'Alice';