小编Ars*_*nko的帖子

数据库中每行更改的记录一般是如何存储的?

在我正在处理的一个项目中,必须跟踪数据库某些表中行的每次更改以进行进一步审计或回滚。必须很容易找到谁修改了行,从哪个 IP 地址和时间,并且能够恢复以前的版本。

例如 Stack Exchange 使用了类似的东西。当我改变别人的问题时,有可能发现我改变了它,并且回滚了改变。

考虑到我当前的架构与普通业务应用程序具有大致相同的属性(如下),用于将每个更改存储在数据库中的通用技术是什么

  • 对象的大小相对较小:nvarchar(1000)例如可能有一些,但不是大量的二进制数据,这个直接存储在磁盘上,直接访问,而不是通过 Microsoft SQL filestream
  • 数据库负载非常低,整个数据库由服务器上的一个虚拟机处理,
  • 访问以前版本不必像访问最新版本一样快,但仍然必须是最新的¹ 并且不能太慢²。

<tl-博士>

我想过以下案例,但我对这些场景没有真正的经验,所以我想听听其他人的意见:

  1. 将所有内容存储在同一个表中,按 ID 和版本区分行。IMO,这是非常愚蠢的,迟早会在性能水平上受到伤害。使用这种方法,也不可能为最新项目和版本跟踪设置不同的安全级别。最后,每个查询的编写都会更加复杂。实际上,要访问最新数据,我将被迫按 ID 对所有内容进行分组,并在每个组中检索最新版本。

  2. 将最新版本存储在一个表中,并在每次更改时将过时版本复制到另一个模式中的另一个表中。缺陷是每次我们都会存储每个值,即使它没有改变。设置不变值null不是一个解决方案,因为我还必须当值更改为跟踪nullnull

  3. 将最新版本存储在一个表中,并将更改的属性列表及其以前的值存储在另一个表中。这似乎有两个缺陷:最重要的一个是,对同一列中不同类型的先前值进行排序的唯一方法是使用binary(max). 第二个是,我相信,在向用户显示以前的版本时,使用这种结构会更加困难。

  4. 执行与前两点相同的操作,但将版本存储在单独的数据库中。在性能方面,为了避免通过将以前的版本放在同一数据库中而减慢对最新版本的访问速度可能会很有趣;尽管如此,我认为这是一个过早的优化,只有在有证据表明在同一数据库中拥有旧版本和最新版本是瓶颈时才必须进行优化。

</tl-dr>


¹ 例如,将更改存储到日志文件中是不可接受的,就像对 HTTP 日志所做的那样,并在服务器负载最低的晚上将数据从日志刷新到数据库中。有关不同版本的信息必须立即或几乎立即可用;几秒钟的延迟是可以接受的。

² 信息不是很频繁,只有特定的用户组才能访问,但是,强迫他们等待 30 秒才能显示版本列表是不可接受的。同样,几秒钟的延迟是可以接受的。

schema sql-server-2008 sql-server optimization

10
推荐指数
1
解决办法
4514
查看次数

与非动态查询相比,存储过程的执行计划缓存“更好”吗?

阅读有关 Microsoft SQL Server 执行计划缓存的不同解释,我对使用存储过程而不是非动态查询的好处感到困惑。

我所说的非动态查询是指一个完全参数化的查询字符串,它不会通过多次调用而改变。

据我了解:

  1. 为存储过程和普通查询都缓存了执行计划。

  2. 对于存储过程,执行计划是预先计算好的,这比第一次调用存储过程时的普通查询略有优势。

来源在我看来相当矛盾:

  • MSDN上的Execution Plan Caching and Reuse 文章对参数化查询和存储过程没有区别。这些小节强调了参数化查询的重要性,以便 SQL Server 可以轻松地缓存执行计划。

  • SQL Server 查询执行计划 – Basics声称相反(强调我的):

    在执行即席查询时,查询计划是基于完整代码创建的,因此不同的参数或代码的任何更改都将阻止重用现有计划

  • 在 DBA.StackExchange 上,与存储过程的好处相关的答案的评论表明参数化查询与存储过程具有完全相同的效果。

因此,在执行计划没有从缓存中抛出的情况下,为了实验,我想运行数十亿次相当复杂的查询,该查询将从执行计划中受益,并且需要一个改变的参数每次使用存储过程而不是普通的参数化查询在执行计划缓存方面会有什么好处吗?


¹ 在执行计划范围之外,使用存储过程会带来较小的性能优势,例如在网络占用方面:传递存储过程的名称及其参数略好于传递整个查询。这些好处超出了我的问题范围,这纯粹是关于执行计划缓存。

sql-server execution-plan sql-server-2012 plan-cache

7
推荐指数
1
解决办法
3269
查看次数

如何使 FILESTREAM 文件丢失/损坏的数据库联机?

我损坏了数据库中与 FILESTREAM 相关的文件。

.mdf.ldf文件仍然完好,但是当我尝试上网的数据库,它抱怨,说有关FILESTREAM的文件是不正确的。

我不关心存储在 FILESTREAM 中的数据,但我关心其他数据。我可以从.mdf.ldf文件中取回它吗?如何?

当我执行:

sp_attach_db @dbname = 'Demo',
             @filename1 = N'<File path>.mdf',
             @filename2 = N'<File path>.ldf'
Run Code Online (Sandbox Code Playgroud)

答复是:

Msg 5120, Level 16, State 105, Line 1
Unable to open the physical file "<Location>". Operating system error 2: "2(The system cannot find the file specified.)".
Msg 5105, Level 16, State 14, Line 1
A file activation error occurred. The physical file name '<Location>' may be incorrect. Diagnose and correct additional …
Run Code Online (Sandbox Code Playgroud)

sql-server-2008 sql-server corruption filestream

6
推荐指数
1
解决办法
2564
查看次数

为什么CDC在启用时什么都不记录?

我在 Microsoft SQL 2008 数据库中的某些表上启用了变更数据捕获。以下两个查询都返回 1:

select top 1 is_cdc_enabled from sys.databases where name = N'<DatabaseName>'

select top 1 T.[is_tracked_by_cdc]
    from sys.tables as T
        left join sys.schemas as S
        on T.[schema_id] = S.[schema_id]
    where S.[name] = N'<SchemaName>' and T.[name] = N'<TableName>'
Run Code Online (Sandbox Code Playgroud)

但是当我更改相关表的数据时,cdc.<SchemaName>_<TableName>_CT仍然为空。

为什么?

sql-server-2008 sql-server

5
推荐指数
1
解决办法
1576
查看次数

如何撤消在受控环境中对数据库所做的每项更改?

我在做一个产品的系统测试,有几个测试严重改变了一个演示数据库的数据。

创建查询的数据非常复杂,这些查询将撤消测试所做的更改;此外,这些测试可能会发生变化。

使用备份/恢复不是一种选择,因为恢复数据库需要 30 秒,这在自动化测试的上下文中太长了。

使用也insert into select很复杂:同样,测试可能会发生变化,并且可能会影响他们现在不影响的表;出于性能原因,以这种方式复制整个数据库也不是一种选择。

Microsoft SQL Server 具有快照功能,但鉴于我在本地主机上没有企业版,我无法使用它。我也不能使用事务,因为系统测试涉及两个应用程序,它们之间有复杂的交互。当然,它们不共享相同的连接。

可以做些什么来快速撤消数据库的最后更改?

为了使问题更容易,

  1. 数据库处于受控环境中:

    • 它在本地主机上,所以我是唯一可以访问它的人,

    • 唯一的变化来自系统测试。所有更改都可能(并且预计会)丢失。

    • 可以选择任何恢复模式。

  2. 准备(例如某种备份)可能需要很长时间,甚至是一项手动任务,因为它很少执行。重要的是从这一点开始撤销更改的速度,因为它是在每次影响数据库的测试之后完成的。

sql-server sql-server-2008-r2 snapshot restore

4
推荐指数
2
解决办法
6008
查看次数

只有两台机器的副本集有意义吗?

很多 MongoDB 教程在谈到副本集时,都给出了两台机器的示例:一台最初初始化为主要机器,另一台最初创建为辅助机器。

据我了解:

  • 如果主要成员意外死亡,次要成员无论如何都不会选举自己成为新的主要成员,因为它不会拥有多数(两台机器的副本集中的两个)。

  • 如果主成员不可用,即使使用read_preference=ReadPreference.SECONDARY.

  • 重新创建主成员无论如何都行不通:它不能添加到现有的副本集中,因为它缺少主成员;它也不能rs.initiate();,因为它将创建具有不同 ID 的不同副本集。

因此,在现实生活中,复制集中只有两个成员是否有意义?或者这种情况只是理论上的,在实践中人们会期望在每个副本集中看到至少三个成员?

mongodb failover high-availability

4
推荐指数
1
解决办法
4207
查看次数

为什么用左连接做四个简单的选择而不是一个选择更快?

我需要从A包含三个外键的表中找到一个值到另外两个表BC.

为了实验,我测试了两种查询值的方法:

多个查询:

declare @start int = (select top 1 [Id] from [B] where [Day] = '2015-01-01')
declare @end int = (select top 1 [Id] from [B] where [Day] = '2017-06-14')
declare @category int = (select top 1 [Id] from [C] where [Title] = 'Hello, World!')

select top 1 [Name]
from [A]
where [StartId] = @start
    and [EndId] = @end
    and [CategoryId] = @category
    and [Day] = '2016-05-27'
Run Code Online (Sandbox Code Playgroud)

单个查询:

select top 1 [Name]
from …
Run Code Online (Sandbox Code Playgroud)

performance sql-server execution-plan sql-server-2012 query-performance

2
推荐指数
1
解决办法
193
查看次数