我有一个数据库表AB,它跟踪A和B随着时间的推移的关联:
create table AB columns (
ARef ..., -- FK of A
BRef ..., -- FK of B
Since as Timestamp,
Until as Timestamp,
SomeAttrib1 ...,
SomeAttrib2 ...
);
Run Code Online (Sandbox Code Playgroud)
我想声明一个唯一的键,以便相同的 A 和 B在相同的时间间隔内只能关联一次 。
我可以使用什么策略来表达这种约束?显然,仅进行 PK 是ARef,BRef,Since,Until不够的 - 这只会防止完全相同间隔的重复。我需要考虑一行的间隔如何与表中其他行的间隔重叠或不重叠。
要考虑的参数:
我正在尝试恢复 GHTorrent 的数据库转储(包含 GitHub 元数据的 CSV 文件)。该commits表拥有超过 8.91 亿行,并且project_commits拥有超过 54 亿行。由于这些表相当大,我必须使用LOAD DATA INFILE外键检查来加载它们。我正在使用MyISAM引擎。将记录导入表后,我尝试为这些表创建索引。
我正在为表运行以下 mysql 命令commits,但它在超过 12 小时内才完成。
CREATE UNIQUE INDEX `sha` ON `ghtorrent_restore`.`commits` (`sha` ASC) COMMENT '';
Run Code Online (Sandbox Code Playgroud)
提交表如下所示:
my.cnf我已阅读有关缓慢索引的其他 stackexchange 问题,并在目录中的文件中设置以下内容/etc/mysql。
[mysqld]
bulk_insert_buffer_size=1G
myisam_sort_buffer_size=8G
key_buffer_size=6G
sort_buffer_size=10M
Run Code Online (Sandbox Code Playgroud)
由于上一个命令没有及时完成,我不得不从控制台使用 ctrl+z 来停止它。我检查了 MySQL Workbench 上的表,它没有显示为损坏,但它显示索引长度约为 36GB。
导入该表大约需要 25 分钟,因此我预计索引不会超过一个小时,但我现在运行“创建唯一索引”命令大约 2 小时,没有任何进展迹象。
当我运行该命令时,mysqld 占用大量 cpu 并且不断占用内存。达到 6GB 左右后,它变得不那么活跃,似乎几乎什么也不做。
以下是该命令(在下图中选择的一个)在 mysql 工作台中的外观。
我正在一台具有 16GB RAM 的 Linux Mint 17.03 机器上运行 Mysql …
我正在运行 PostgreSQL 9.1.4。
我有一个包含许多现有行的表,以及一堆其他带有指向它的外键的表,我正在尝试:
1 - 删除当前主键上的 pkey 约束,因为它当前不是串行类型。
2 - 添加一个串行类型的列并将该新列作为主键。
3 - 将步骤 #1 的旧列设置为 UNIQUE 并为所有具有指向我的表的外键的表重新创建外键。事实上,这些表都有两个指向我的表的外键:一个指向当前作为主键的旧列,另一个指向新的串行类型列
我已经成功创建了一个执行此操作的脚本,但我想知道:
a) 在上面的第 1 步删除 pkey 约束是否也会删除与该主键关联的索引?
b)如果没有,有没有办法重用该索引?在第 3 步添加回 UNIQUE 约束后,会创建一个新索引还是使用之前存在的索引?除了创建的新列(串行主键)外,表中没有任何内容被更改。
编辑(一些澄清):
postgresql index database-design primary-key unique-constraint
我有UNIQUE一个表上的多个字段的约束。我想更改此约束中的字段(删除一个字段)的图像。通常我会做这样的事情:
DROP INDEX unique_name ON table_name;
CREATE UNIQUE INDEX unique_name ON table_name (field1, field2, ...);
Run Code Online (Sandbox Code Playgroud)
但这是两个语句,在执行第一个语句后将UNIQUE不再有约束,因此任何INSERT可能都可能破坏约束,直到新的UNIQUE创建的。
还有另一种方法可以做到这一点:
ALTER TABLE table_name
DROP INDEX unique_name,
ADD CONSTRAINT unique_name UNIQUE (field1, field2, ...);
Run Code Online (Sandbox Code Playgroud)
这是一种说法。问题是:这个语句会执行原子操作吗?我所说的原子是指完全没有约束的时候就没有时间窗口UNIQUE。
我正在auto-increment向大表中添加一个字段。
该字段已填充(大约 1-500M)并且新插入的内容正在正确地手动递增。为了验证,我运行了一个查询以显示任何重复项:
mysql> SELECT new_id, COUNT(*) AS count FROM my_table GROUP BY new_id HAVING count > 1;
# No Results
Run Code Online (Sandbox Code Playgroud)
当我手动查看最新记录时,我会看到看起来像自动递增的BIGINT(20)字段。NULL该列中不存在 's 。
然而,当我尝试将索引更改为 a UNIQUE INDEX(从非唯一索引,但具有唯一值)时,它会触发DUPLICATE KEY错误。并且重复键始终为MAX(new_id)+1,因此有问题的重复项的aSELECT始终不返回任何结果。
这是我正在运行的内容:
mysql> SELECT MAX(new_id) FROM my_table;
+-------------+
| MAX(new_id) |
| 512345678 |
+-------------+
1 row in set (0.00 sec)
mysql> ALTER TABLE my_table
DROP INDEX `idx_new_id`,
ADD UNIQUE INDEX `idx_new_id ` USING BTREE (`new_id `); …Run Code Online (Sandbox Code Playgroud) 在表中Orders,我存储了我们从所有商店收到的订单。由于一个订单可以有多个行,列中有OrderID和OrderLineID
在那里OrderID可以复制,但OrderLineID必须是一个顺序中是唯一的。
由于订单可以修改,存储过程首先检查收到的订单OrderLineID是否已经存在于表中,然后决定插入还是更新。为此,我们:
然后是主表:
IF NOT EXISTS (Select 1 from Orders where OrderLineID=@OrderLineID ......)
INSERT INTO Orders () VALUES ()
ELSE UPDATE Orders SET ... WHERE OrderLineID=@OrderLineID
Run Code Online (Sandbox Code Playgroud)
或者该MERGE功能是否提供更好的性能/控制?
但问题如下:
由于线路问题/服务器繁忙等,Order消息(或修改)可能会被多次发送,我们不知道按哪个顺序发送。因此,为了避免Order修改后到达,从而覆盖修改,我们添加了一个时间列:
IF NOT EXISTS (Select 1 from Orders where OrderLineID=@OrderLineID)
INSERT INTO Orders () VALUES ()
ELSE UPDATE Orders SET ... WHERE OrderLineID=@OrderLineID AND LastModified<@CreatedTime
Run Code Online (Sandbox Code Playgroud)
这样,如果后一条消息比前一条消息旧,则对表没有影响。
但是,消息及其修改可能会在很短的时间内发送两次(或更多),以至于后一条消息在保存前一条消息之前到达。因此,对于存储过程的两次执行,它 …
查看 Microsoft 文档,它说创建唯一约束时,会自动创建唯一索引。
是否有一个技巧/解决方法来拥有一个唯一的约束而不是一个唯一的索引,所以它不占用空间?
我对数据库开发完全陌生,我基本上正在尝试建立一个问题库。
问题必须根据类别、主题和主题进行分类。由于每个类可以有许多主题,并且每个主题可以在许多类中,因此我制作了一个名为 tb_SubjectClass 的连接表,其中主题和类是主键。
为了唯一标识任何章节,我需要主题和类的组合,因此我创建了 tb_Chapters,其中章节、主题和类作为主键,主题和类来自 tb_SubjectClass。然后我用 tb_Topics 重复了同样的事情,因为每个主题只能用主题、类和章节的组合来标识。
我把关系图放在下面。知道我期望在这个数据库中存储大约 50000 个问题(带有方程和图表)也可能是相关的。
主要问题:如果我决定坚持使用复合键/复合键,我的设计是否合适或可以进一步改进?
附带问题:在我的情况下,最好的方法是什么,考虑到以下因素:
我主要一直都在数据库设计教程上tekstenuitleg.net和视频教程由WiseOwlTutorials。我最近也开始阅读Jan L. Harrington所著的Relational Database Design Clearly Explained一书。
database-design sql-server sql-server-2014 unique-constraint
所以我们目前有以下几点:
MYTABLE
COLUMN: ID (INTEGER Primary key, auto-incrementer)
COLUMN: START (DATE)
COLUMN: COMPANYID (INTEGER, Foreign key to COMPANY)
COLUMN: DELETED (INTEGER)
CHECK: DELETED = 0 OR DELETED = 1
Run Code Online (Sandbox Code Playgroud)
现在,要求允许无限删除记录,但只允许每个日期+公司的单个未删除记录。
我建议将架构更改为:
MYTABLE
COLUMN: ID (INTEGER Primary key, auto-incrementer)
COLUMN: START (DATE)
COLUMN: COMPANYID (INTEGER, Foreign key to COMPANY)
COLUMN: ACTIVE (Nullable INTEGER)
CHECK: ACTIVE = 1 OR ACTIVE IS NULL
UNIQUE: START, COMPANYID, ACTIVE
Run Code Online (Sandbox Code Playgroud)
虽然我的同事认为这“在约束上做得太过分了”,而我们应该只依赖应用程序中的唯一性检查。
这里有普遍接受的最佳实践吗?
我们定义了一系列配置,其中,在 RESTful API 的驱动下,最终用户可以构建新的修订版本。配置的某些组件可以有多个值;修订涉及具有一对多关系的多个表。
因为配置被运往别处,修订被标记为已部署,并且变得不可变。如果用户想对配置进行更改,他们必须创建一个新修订(可以从现有修订中克隆)。每个配置的一个 修订版可以标记为“当前”;这允许用户随意在过去的修订之间切换,或者通过不选择任何修订来完全禁用配置。当前版本已部署,当将不同版本标记为“当前”时,您将替换已部署的配置。
我们已经准备好了一切来强制部署修订的不变性;当您第一次使用修订作为当前修订时,该deployed列会自动转换为TRUE,并且所有进一步的INSERT,UPDATE和DELETE与修订相关表中部署的修订 ID 匹配的行的操作都将被阻止。
但是,用于公共名称表中的name列的任何值在所有当前配置的所有“当前”修订中都必须是唯一的。我正在尝试找出执行此操作的最佳策略。
如果这是从配置到公共名称的简单一对多关系,则可以通过对name列使用唯一约束来解决。相反,这是一种一对多模式,revision充当桥接表,并将current_revision_id一对多对多关系“折叠”为从配置到虚拟的一对多关系公共名称。
这是一组简化的表格,用于说明我们的情况:
Run Code Online (Sandbox Code Playgroud)-- Configurations CREATE TABLE config ( id INT PRIMARY KEY, name VARCHAR(100), current_revision_id INT ); -- Have multiple revisions CREATE TABLE revision ( id INT PRIMARY KEY, config_id INT NOT NULL REFERENCES config(id), created_at TIMESTAMP WITH TIME ZONE …
index ×3
mysql ×3
sql-server ×3
mysql-5.7 ×2
postgresql ×2
alter-table ×1
concurrency ×1
datatypes ×1
db2-midrange ×1
duplication ×1
innodb ×1
myisam ×1
primary-key ×1
trigger ×1