Clickhouse一级索引优化方案

article/2025/11/5 15:33:20

文章目录

  • Clickhouse的应用场景
  • 1、索引介绍
    • 1.1、主要索引
    • 1.2、二级索引
    • 1.2.1、数据跳过索引
  • 2、一级索引优化
    • 2.1、CK的sql的优化方向
    • 2.2、验证过程
      • 结论:
    • 2.3、如何修改排序键
      • 总结:
    • 3、二级索引(跳数索引)
  • 知识点
    • 查看Clickhouse的执行计划
    • 查询中的主键和索引
    • 选择主键
      • 分区
    • 将索引用于部分单调的主键

Clickhouse的应用场景

绝大多数是读请求
数据以相当大的批次(> 1000行)更新,而不是单行更新;或者根本没有更新。
已添加到数据库的数据不能修改。
对于读取,从数据库中提取相当多的行,但只提取列的一小部分。
宽表,即每个表包含着大量的列
查询相对较少(通常每台服务器每秒查询数百次或更少)
对于简单查询,允许延迟大约50毫秒
列中的数据相对较小:数字和短字符串(例如,每个URL 60个字节)
处理单个查询时需要高吞吐量(每台服务器每秒可达数十亿行)
事务不是必须的
对数据一致性要求低
每个查询有一个大表。除了他以外,其他的都很小。
查询结果明显小于源数据。换句话说,数据经过过滤或聚合,因此结果适合于单个服务器的RAM中

1、索引介绍

1.1、主要索引

通过按主键对数据进行物理排序,可以提取其特定值或值范围的数据,延迟低,小于几十毫秒。(也就是下文分析的内容)

  • 改进数据压缩。
    ClickHouse按主键对数据进行排序,因此一致性越高,压缩效果越好。

1.2、二级索引

与其他数据库管理系统不同,ClickHouse 中的二级索引不指向特定的行或行范围。相反,它们允许数据库提前知道某些数据部分中的所有行都与查询筛选条件不匹配,并且根本不读取它们,因此它们被称为数据跳过索引

1.2.1、数据跳过索引

对于系列(**MergeTree)中的表,可以指定数据跳过索引。

这些索引聚合有关块上指定表达式的一些信息,块由粒状组成(粒度的大小是使用表引擎中的设置指定的)。然后,这些聚合用于查询,通过跳过查询无法满足的大块数据块来减少要从磁盘读取的数据量。
ck默认索引粒度:8192 = 1024 * 8
也就是查看表中自动生成的 SETTINGS index_granularity = 8192

2、一级索引优化

总结一下可以优化的地方:

  1. 一级索引
  2. 二级索引
  3. 可以根据现有字段直接分区 PARTITION BY 字段
  4. 可以根据函数分区 PARTITION BY toYYYYMM(EventDate) toYYYYMM是函数,(eventDate)属性需要是Data类型

目前业务中可优化的选项:

  • 日期尽量都使用date类型,目前使用的是Int64(待研究)
    按月分区的键仅允许读取那些包含适当范围的日期的数据块。在这种情况下,数据块可能包含许多日期(最多一整个月)的数据。在块中,数据按主键排序,主键可能不包含日期作为第一列。因此,使用仅具有未指定主键前缀的日期条件的查询将导致读取的数据多于单个日期的数据

  • 针对常查询的字段,使用ORDER BY(c1, c2, xxx) 创建索引,括号中从左到右的优先级会导致查询效率有别;
    注意:

  • 有Nullable的字段,不能创建索引,一些查询字段不要设置Nullable()

2.1、CK的sql的优化方向

  • 分区,原则是尽量把经常一起用到的数据放到相同区(也可以根据where条件来分区),如果一个区太大再放到多个区

大量分区是一种常见的误解。这将导致严重的负面性能影响,包括服务器启动速度慢、插入查询速度慢和选择查询速度慢。表的建议分区总数在1000以下。请注意,分区并不是为了加速SELECT查询(按键排序足以使范围查询变得快速)。分区用于数据操作(删除分区等)

  • 主键(索引,即排序)order by字段选择: 就是把where 里面肯定有的字段加到里面,where 中一定有的字段放到第一位,注意字段的区分度适中即可 区分度太大太小都不好,因为ck的索引时稀疏索引,采用的是按照固定的粒度抽样作为实际的索引值,不是mysql的二叉树,所以不建议使用区分度特别高的字段。

    • 值得一提的是,通常只有在使用SummingMergeTreeAggregatingMergeTree 的时候,才需要同时设置ORDER BYPRIMARY KEY。显式的设置PRIMARY KEY,是为了将主键和排序键设置成不同的值,是进一步优化的体现。(PS:因为我们使用的引擎并不是上面几种,省略PRIMARY KEY。默认情况下,主键与排序键(ORDER BY)相同,所以通常直接使用ORDER BY代为指定主键。)
    • 创建索引尽量选择基数大的,也就是重复相对较多的(因为是稀疏索引) 在mysql中正好是相反的

也就是说,业务中经常需要查询的字段需要放在order by靠前位置。

举个例子:统计了一下业务中的风险实际表的查询sql语句,按照优先级高到低整理出来的字段

create_time , score , vehicle_id,id

也就是说需要这么写:

order  by(create_time , score , vehicle_id,id).

官网原话:长主键会对插入性能和内存消耗产生负面影响 , 但主键中的额外列不会影响查询期间的ClickHouse 性能。

2.2、验证过程

下面只取两个字段create_time,id来验证

创建4个表,插入相同的204w条数据。(开启trace log,查看查询从机器上面读取的条数,不会弄),暂时以执行时间来参考。

img

4个表的排序情况为:

表1: ORDER BY (id)

表2: ORDER BY (id,create_time)

表3: ORDER BY (create_time)

表6: ORDER BY (create_time,id) //推荐

CREATE TABLE hf_ai_hbs.t_base_data_record1
(`id` Int64 COMMENT '事件ID',`time` Int64 COMMENT '数据记录时间,单位毫秒',...省略了一些字段...`create_time` Int64 DEFAULT 0 COMMENT '创建时间,毫秒时间戳,设备事件时间'
)
ENGINE = ReplacingMergeTree
ORDER BY id
SETTINGS index_granularity = 8192
CREATE TABLE hf_ai_hbs.t_base_data_record2
(`id` Int64 COMMENT '事件ID',`time` Int64 COMMENT '数据记录时间,单位毫秒',...省略了一些字段...`create_time` Int64 DEFAULT 0 COMMENT '创建时间,毫秒时间戳,设备事件时间'
)
ENGINE = ReplacingMergeTree
ORDER BY (id,create_time)
SETTINGS index_granularity = 8192

其余两个字段、属性、数据相同,只是order by里面的内容不同。

-- 执行十次-- SQL 1
SELECT * FROM t_risk_event_record1 trer WHERE id=171972290612035584; 	--执行十次,单位ms:  平均耗时:16.0
SELECT * FROM t_risk_event_record2 trer WHERE id=171972290612035584;	-- 	平均耗时:19.0
SELECT * FROM t_risk_event_record3 trer WHERE id=171972290612035584;	-- 	平均耗时:23 
SELECT * FROM t_risk_event_record6 trer WHERE id=171972290612035584;	--	平均耗时:25.0
-- SQL 2
SELECT * from t_risk_event_record1 trer order by id DESC LIMIT 3;	--平均耗时:35
SELECT * from t_risk_event_record2 trer order by id DESC LIMIT 3;	--56,50,61,52,57,56,54,55,55,54				平均耗时:55
SELECT * from t_risk_event_record3 trer order by id DESC LIMIT 3;	--平均耗时:138
SELECT * from t_risk_event_record6 trer order by id DESC LIMIT 3;	--平均耗时:148
-- SQL 3
SELECT * from t_risk_event_record1 trer order by create_time DESC LIMIT 3;	--执行十次,平均耗时:125.0	129,122,121,125,133,120,119,125,131,125
SELECT * from t_risk_event_record2 trer order by create_time DESC LIMIT 3;	--执行十次,平均耗时:135.0	146,153,130,140,127,130,125,124,130,145
SELECT * from t_risk_event_record3 trer order by create_time DESC LIMIT 3;	--执行十次,平均耗时:54.0		50,43,56,56,57,54,65,50,61,48
SELECT * from t_risk_event_record6 trer order by create_time DESC LIMIT 3;	--执行十次,平均耗时:53.0		56,57,40,63,53,54,47,44,57,59
-- SQL 4
SELECT * from t_risk_event_record1 trer order by create_time,id DESC LIMIT 3;	--执行十次,平均耗时:120
SELECT * from t_risk_event_record2 trer order by create_time,id DESC LIMIT 3;	--执行十次,平均耗时:135
SELECT * from t_risk_event_record3 trer order by create_time,id DESC LIMIT 3;	--执行十次,平均耗时:100
SELECT * from t_risk_event_record6 trer order by create_time,id DESC LIMIT 3;	--执行十次,平均耗时:65
-- SQL 5
SELECT * from t_risk_event_record1 trer order by id,create_time DESC LIMIT 3;	--执行十次,平均耗时:45
SELECT * from t_risk_event_record2 trer order by id,create_time DESC LIMIT 3;	--执行十次,平均耗时:50
SELECT * from t_risk_event_record3 trer order by id,create_time DESC LIMIT 3;	--执行十次,平均耗时:140
SELECT * from t_risk_event_record6 trer order by id,create_time DESC LIMIT 3;	--执行十次,平均耗时:150
-- SQL 6
SELECT * from t_risk_event_record1 trer WHERE (create_time>=1649324393021) AND (create_time <=1649324595021);	--执行十次,平均耗时:35
SELECT * from t_risk_event_record2 trer WHERE (create_time>=1649324393021) AND (create_time <=1649324595021);	--执行十次,平均耗时:34
SELECT * from t_risk_event_record3 trer WHERE (create_time>=1649324393021) AND (create_time <=1649324595021);	--执行十次,平均耗时:25
SELECT * from t_risk_event_record6 trer WHERE (create_time>=1649324393021) AND (create_time <=1649324595021);	--执行十次,平均耗时:20

img

结论:

  • sql1中,根据id查询,四种情况的查询效率相差不大
  • sql2中,根据id排序,因为建表时候,表1和表2排序键前面都是id,所以查询效率明显比表3、6要好。sql3中情况刚好相反
  • sql4中,表3、4的order by 排序键的create_time比较靠前,所以,他们的查询效率相对表1、2快了两倍多,sql5中相反。
  • sql6中,表3、4的order by 排序键的create_time比较靠前
  • 除了在sql2根据id排序的情况下,表6排序键的查询效率在这几个sql中都是比较快的

2.3、如何修改排序键

img这里有几个问题

  1. 看这段话排序键的AlTER对象是新增的列才行,而不能像二级索引(跳数索引)一样可以随意更改成其他字段

排序键可以更新除了主键外的键。比如主键是id,可以从order by(id,name)更新成(id,age);但是更新的字段必须是新增的列

  1. 更改完排序键后索引文件应该没有任何变化,这时我们设置的新排序规则应该对查询没有任何作用?
  2. 如何才能根据新设置的排序键进行重建索引?
  3. ClickHouse 在什么情况下会自动重建索引?

修改排序键 sql 如下:

ALTER TABLE 数据库.表名
ADD COLUMN age Int16, 
MODIFY ORDER BY (id, age)

总结:

  • 针对常查询的字段,使用ORDER BY(c1, c2, xxx) 创建索引,而且业务中经常需要查询的字段需要放在order by靠前位置。
  • 长主键会对插入性能和内存消耗产生负面影响 , 但主键中的额外列不会影响查询期间的ClickHouse 性能。

参考链接:
clickhouse使用经验总结:https://blog.csdn.net/TankRuning/article/details/111317090

clickhouse的索引结构和查询优化:https://blog.csdn.net/h2604396739/article/details/86172756

从Clickhouse执行计划看跳数/稀疏索引的效果:https://www.gbase8.cn/6596

Clickhouse orderby之谜:https://zhuanlan.zhihu.com/p/379848085

clickhouse 在order by非常慢的情况下优化:https://www.cnblogs.com/niutao/p/15313070.html

ClickHouse的执行计划以及优化策略:https://www.cnblogs.com/traditional/p/15264282.html

clickhouse分区操作实践:https://blog.csdn.net/m0_37813354/article/details/110847747

3、二级索引(跳数索引)

跳数索引:能够快速跳过无用的数据区间(跳跃粒度是我们设置的,默认8192)。有些区间可能不会被扫描到,提高我们查询的效率

类似布隆过滤器,所有跳数索引的原则都是“排除法”,即尽可能的排除那些一定不满足条件的索引粒度。

告诉我们某个数据一定不存在或者可能存在(注意:布隆过滤器是不能判断某条数据一定存在的,存在误报率 (false_positive) )。相比于传统的 List、Set、Map 等数据结构,布隆过滤器更高效、占用空间更少,因为不需要存储原始值,但是缺点是其返回的结果是概率性的,而不是确切的。

知识点

查看Clickhouse的执行计划

在前面加explain

img

注意其中的数据读取位置,分别是从原始的存储(ReadFromStorage),和预处理的源(ReadFromPreparedSource)。

explain SYNTAX 加sql语句,会输出优化的sql,如果和我们写的一样,说明我们的sql已经是最优的了img

查询中的主键和索引

以主键为例。在这种情况下,排序和索引可以如下图示:(CounterID, Date)

img

如果数据查询指定:

  • CounterID in ('a', 'h')中,服务器读取标记和 范围内的数据。[0, 3)[6, 8)
  • CounterID IN ('a', 'h') AND Date = 3中,服务器读取标记和 范围内的数据。[1, 3)``[7, 8)
  • Date = 3中,服务器读取标记范围内的数据。[1, 10] 取并集

上面的示例表明,使用索引始终比完全扫描更有效。

ClickHouse 不需要唯一的主键。可以使用相同的主键插入多行。

选择主键

主键中的列数没有显式限制。根据数据结构,您可以在主键中包含更多或更少的列。这可能:

  • 提高索引的性能。

如果主键为,则在满足以下条件时,添加另一列将提高性能:(a,b)``c

    • 有些查询在列上具有条件, 例如:c
    • 具有相同值的长数据范围(比长几倍)很常见。换句话说,添加另一列时,可以跳过相当长的数据范围。index_granularity (a,b)
  • 改进数据压缩。

ClickHouse按主键对数据进行排序,因此一致性越高,压缩效果越好。

  • 在CollapseingMergeTree和SummingMergeTree 引擎中合并数据部分时提供其他逻辑。在这种情况下,指定与主键不同的排序建是有意义的。

值得一提的是,通常只有在使用SummingMergeTreeAggregatingMergeTree 的时候,才需要同时设置ORDER BYPRIMARY KEY。

显式的设置**PRIMARY KEY,**是为了将主键和排序键设置成不同的值,是进一步优化的体现。

长主键会对插入性能和内存消耗产生负面影响 , 但主键中的额外列不会影响查询期间的ClickHouse 性能。

可以使用语法创建没有主键的表。在这种情况下,ClickHouse将按插入顺序存储数据。如果要在按查询插入数据时保存数据顺序,请设置max_insert_threads = 1ORDER BY tuple() INSERT ... SELECT

若要按初始顺序选择数据,请使用单线程查询。SELECT

分区

单个插入块的分区太多(超过100个)。该限制由“每个插入块的最大分区数”设置控制。大量分区是一种常见的误解。这将导致严重的负面性能影响,包括服务器启动速度慢、插入查询速度慢和选择查询速度慢。表的建议分区总数在1000以下。。请注意,分区并不是为了加速SELECT查询(按键排序足以使范围查询变得快速)。分区用于数据操作(删除分区等)

img

ENGINE MergeTree() PARTITION BY toYYYYMM(EventDate) ORDER BY (CounterID, EventDate) SETTINGS index_granularity=8192
SELECT count() FROM table WHERE EventDate = toDate(now()) AND CounterID = 34
SELECT count() FROM table WHERE EventDate = toDate(now()) AND (CounterID = 34 OR CounterID = 42)
SELECT count() FROM table WHERE ((EventDate >= toDate('2014-01-01') AND EventDate <= toDate('2014-01-31')) OR EventDate = toDate('2014-05-01')) AND CounterID IN (101500, 731962, 160656) AND (CounterID = 101500 OR EventDate != toDate('2014-05-01'))

ClickHouse 将使用主键索引来修剪不正确的数据,并使用每月分区键来修剪日期范围内的分区。

上面的查询表明,索引甚至用于复杂表达式。对从表中读取数据进行组织,以便使用索引的速度不会比完全扫描慢。

在下面的示例中,无法使用索引。

SELECT count() FROM table WHERE CounterID = 34 OR URL LIKE '%upyachka%'

要检查 ClickHouse 在运行查询时是否可以使用索引,请使用设置force_index_by_date和force_primary_key。

按月分区的键仅允许读取那些包含适当范围的日期的数据块。在这种情况下,数据块可能包含许多日期(最多一整个月)的数据。在块中,数据按主键排序,主键可能不包含日期作为第一列。因此,使用仅具有未指定主键前缀的日期条件的查询将导致读取的数据多于单个日期的数据。

  • 创建分区

建表时使用关键字 PARTITION BY 【分区名称】

  • 使用函数创建分区

比如根据toYYYYMM(date字段)会生成yyyyMM格式的年月日期分区

数据****PARTITION 在ClickHouse中主要有两方面应用:

  1. 在PARTITION KEY上进行分区裁剪,只查询必要的数据。灵活的PARTITION expression设置,使得可以根据SQL PARTITION 进行分区设置,最大化的贴合业务特点。
  2. 对PARTITION 进行TTL管理,淘汰过期的分区数据。

[

](https://blog.csdn.net/m0_37813354/article/details/110847747)

将索引用于部分单调的主键

例如,考虑一个月中的几天。它们在一个月内形成单调序列,但在更长的时间内不形成单调序列。这是一个部分单调的序列。如果用户使用部分单调的主键创建表,ClickHouse 将像往常一样创建稀疏索引。当用户从此类表中选择数据时,ClickHouse 会分析查询条件。如果用户想要获取索引的两个标记之间的数据,并且这两个标记都在一个月内,ClickHouse 可以在此特定情况下使用索引,因为它可以计算查询参数和索引标记之间的距离。

如果查询参数范围中的主键值不表示单调序列,则 ClickHouse 不能使用索引。在这种情况下,ClickHouse使用完全扫描方法。

ClickHouse 不仅将此逻辑用于月份序列中的天数,还对表示部分单调序列的任何主键使用此逻辑。


http://chatgpt.dhexx.cn/article/L1TAIvaw.shtml

相关文章

Mysql详解——索引优化

本篇文章是对Mysql索引的创建以及优化进行一个介绍&#xff0c;关于索引的底层原理可以看我另一篇文章&#xff1a;Mysql详解——索引详解 文章目录 一、索引的创建和设计原则1. 索引的声明和使用1.1 索引的分类&#xff1a;1.2 索引的创建&#xff1a;在创建表时创建索引&…

MySQL SQL和索引优化总结

文章目录 一、SQL语句和索引的优化二、应用优化三、MySQL Server优化1. 自适应哈希索引2. redo log3. MySQL查询缓存4. 索引和数据缓存5. MySQL线程缓存6. 并发连接数量和超时时间 首先我们需要知道MySQL主要是从以下3个方面进行优化&#xff1a; SQL语句和索引应用优化&#…

mysql嵌套子查询索引_SQL 子查询,索引优化

场景 索引优化 单列索引 多列索引 索引覆盖 排序 场景 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表 create table Course( c_id int PRIMARY KEY, name varchar(10) ) 数据100条 学生表: create table Student( id int PRIMARY KEY, name varchar(10) ) 数据70000条 …

索引如何优化

前言 索引的相信大家都听说过&#xff0c;但是真正会用的又有几人&#xff1f;平时工作中写SQL真的会考虑到这条SQL如何能够用上索引&#xff0c;如何能够提升执行效率&#xff1f; 此篇文章详细的讲述了索引优化的几个原则&#xff0c;只要在工作中能够随时应用到&#xff0c…

MySQL高级-索引优化(超详细)

性能分析 MySQL Query Optimizer Mysql中由专门负责优化SELECT语句的优化器&#xff0c;主要功能就是通过计算分析系统中收集到的统计信息&#xff0c;为客户端请求的Query提供他认为最优的执行计划&#xff08;他认为最优的&#xff0c;但**不一定是DBA觉得最优的&#xff0…

mysql locate索引_MYSQL索引优化

1.查看sql的执行频率 MySQL 客户端连接成功后,通过 show [session|global] status 命令可以提供服务器状态信息。show [session|global] status 可以根据需要加上参数“session”或者“global”来显示 session 级(当前连接)的计结果和 global 级(自数据库上次启动至今)的统计结…

索引优化详解

一、EXPLAIN 做MySQL优化&#xff0c;我们要善用 EXPLAIN 查看SQL执行计划。 下面来个简单的示例&#xff0c;标注(1,2,3,4,5)我们要重点关注的数据 type列&#xff0c;连接类型。一个好的sql语句至少要达到range级别。杜绝出现all级别 key列&#xff0c;使用到的索引名。如果…

索引优化原则

1、全值匹配 查询语句尽量使用全值匹配。 2、左前缀原则 如果一个索引是组合索引&#xff0c;索引了多列&#xff0c;要遵循左前缀原则&#xff0c;即查询从索引的左前缀开始&#xff0c;不能跳过索引中间的列。 3、不要在索引列上操作 操作包括&#xff1a;计算、函数、自动…

项目中常用的MySQL优化你知道多少?

项目中常用的MySQL优化 文章目录 项目中常用的MySQL优化前言一、mysql优化是什么&#xff1f;二、优化步骤1.EXPLAIN2.SQL语句中IN包含的值不应太多3.SELECT语句务必指明字段名称4.如果排序字段没有用到索引&#xff0c;就尽量少排序5.如果限制条件中其他字段没有索引&#xff…

一文带你你搞懂索引如何优化!!!

前言 索引的相信大家都听说过&#xff0c;但是真正会用的又有几人&#xff1f;平时工作中写SQL真的会考虑到这条SQL如何能够用上索引&#xff0c;如何能够提升执行效率&#xff1f;此篇文章详细的讲述了索引优化的几个原则&#xff0c;只要在工作中能够随时应用到&#xff0c;相…

使用AJAX实现数据的增删改查

主页&#xff1a;index.html <!DOCTYPE html><html> <head> <meta charset"UTF-8"> <title></title> <script src"http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> </head> <body…

合肥工业大学数据库上机实验3(第3次实验)

大三上学期的实验了&#xff0c;一直没来得及放到博客上面&#xff0c;博主所在学校的数据库实验都很简单。&#xff08;不明白为什么截图上传之后为什么那么糊&#xff09; 文章目录 实验9&#xff1a;触发器的创建与使用1. 实验目的2. 实验要求3. 实验内容4. 实验步骤5. 实验…

第三章课后题

3.有两个关系S(A,B,C,D)和T(C,D,E,F)&#xff0c;写出与下列等价的SQL表达式。 &#xff08;1&#xff09; σ A 10 ( S ) \sigma_{A10}(S) σA10​(S) 对行的选择&#xff0c;列全部显示。 SELECT * FROM S WHERE A10;&#xff08;2&#xff09; Π A , B ( S ) \Pi_{A,B}(…

SQL 数据库上机实验(查询操作)

大二数据库上机实验 实验一实验二 实验一 实验步骤&#xff1a; 1&#xff1a;创建数据库“shiyan2”&#xff1b; 2&#xff1a;创建数据表’s’,’p’,’j’&#xff1b; 3&#xff1a;创建数据表’spj’并设定’sno’,’pno’,’jno’三列为外键&#xff0c;分别关联于s表的…

实验3 SQL的复杂多表查询以及视图

第1关 查询所有“红色”的15公斤及以上的零件名 任务描述 查询所有“红色”的15公斤及以上的零件名 相关知识 零件表P由零件代码&#xff08;PNO&#xff09;、零件名(PNAME)、颜色(COLOR)、重量(WEIGHT)组成&#xff1b; P表如下图&#xff1a; 现已构建P表&#xff0c;结构信…

【系统分析师之路】第十五章 复盘数据库系统(关系数据库应用)

【系统分析师之路】第十五章 复盘数据库系统&#xff08;关系数据库应用&#xff09; 复盘数据库系统—关系数据库应用 【系统分析师之路】第十五章 复盘数据库系统&#xff08;关系数据库应用&#xff09;前言部分 历年真题考点分析1&#xff09;考点分析2&#xff09;重要知识…

数据库系统概论练习3

一、填空题 能够唯一标识实体的属性或属性组称为____实体的码______。如果两个关系没有公共属性&#xff0c;则其自然联接操作与____笛卡尔积_____操作等价。SQL中聚合函数“COUNT&#xff08;*&#xff09;”的功能是___统计元组个数________。关系模式如果为1NF&#xff0c;则…

数据库第七周作业——第三章课后习题

3.有两个关系S&#xff08;A,B,C,D&#xff09;和T&#xff08;C,D,E,F&#xff09;,写出与下列查询等价的SQL表达式&#xff1a; (1&#xff09;σ A10(S&#xff09; SELECT * FROM S WHERE A10;(2&#xff09;π A , B ( S ) SELECT A,B FROM S;(3&#xff09;S ⋈ T SEL…

第三章作业【数据库原理】

第二章作业【数据库原理】 前言推荐第三章作业第3章第1题简答题第3章第2题&#xff08;关系代数->SQL代码&#xff09;第3章第3题&#xff08;创建SPJ数据库中的四张表&#xff09;模拟数据第3章第4题&#xff08;SPJ数据库上完成查询&#xff09;第3章第5题&#xff08;SPJ…

设有一个工程供应数据库系统,包括如下四个关系模式:S(Sno,Sname, Status,City) ;P(Pno,Pname,Color ,Weight);J(Jno,Jname, Ci

设有一个工程供应数据库系统&#xff0c;包括如下四个关系模式&#xff1a; S(Sno&#xff0c;Sname&#xff0c; Status&#xff0c;City) &#xff1b; P(Pno&#xff0c;Pname&#xff0c;Color &#xff0c;Weight)&#xff1b; J(Jno&#xff0c;Jname&#xff0c; City) …