标签: sql-server

为什么在创建临时表的存储过程末尾截断临时表会更快地释放临时数据库空间?

SQL Server 缓存在存储过程中创建的临时表,并且仅在过程结束和随后执行时重命名它们。我的问题与 tempdb 空间何时被释放有关。我读到该表在程序结束时被截断。我在评论中读到这是在每个会话的基础上处理的,并且在 MSDN上看到了一个关于是否需要清理的问题。但是如果它从来没有被同一个会话执行过两次呢?

我还听说有一个后台垃圾收集进程,一旦表超出范围,就会释放该空间。

在创建它的存储过程结束时截断临时表似乎会导致表在 tempdb 中用于数据的空间比不使用 truncate 语句时释放的空间更快,尽管与预期相反。为什么?

使用或不使用这种截断语句的相对性能影响是什么?使用 SNAPSHOT 隔离时,tempdb 经常受到压力,我认为尽快从大型临时表中释放 tempdb 中使用的空间将防止 tempdb 不必要的增长。这种潜在的空间节省是否会以性能为代价?

这是一些重现问题的代码(主要来自@TheGameiswar,有一些更改):

SET NOCOUNT ON;
GO
ALTER PROC usp_test
AS
BEGIN
    IF object_id('tempdb..#temp') IS NOT NULL
        DROP TABLE #temp

    SELECT *
    INTO #temp
    FROM [dbo].[Event_28] -- This is a table with 15313 rows, using 35648 KB according to sp_spaceused

    --SELECT SUM(user_object_reserved_page_count) AS [user object pages used]
    --  ,(SUM(user_object_reserved_page_count) * 1.0 / 128) …
Run Code Online (Sandbox Code Playgroud)

sql-server stored-procedures truncate tempdb temporary-tables

12
推荐指数
1
解决办法
6511
查看次数

查找数据库中所有表的未压缩大小

在 Dynamics AX 中有一个缓存机制,可以将表配置为加载到内存中并缓存。此缓存限制为一定数量的 KB,以防止出现内存问题。我正在谈论的设置被调用entiretablecache并在请求单个记录时将整个表加载到内存中。

直到最近,我们依靠一些脚本来验证具有此设置的表的大小,以查看表大小是否高于此限制。

然而,现在,压缩开始发挥作用,诸如sp_spaceused或sys.allocation_units 之类的东西似乎报告了压缩数据实际使用的空间。

显然,应用程序服务器正在处理未压​​缩的数据,因此 SQL Server 中磁盘上的数据大小无关紧要。我需要未压缩数据的实际大小。

我知道sp_estimate_data_compression_savings但正如名字所说,这只是一个估计。
我希望尺寸尽可能正确。

我能想到的唯一方法是一些复杂的动态 SQL 创建与压缩表具有相同结构的未压缩表,将压缩数据插入到影子表中,然后检查影子表的大小。
不用说,这有点乏味,在数百 GB 的数据库上运行需要一段时间。

Powershell 可能是一个选项,但我不想遍历所有表以select *对它们执行 a以检查脚本中的大小,因为这只会淹没缓存并且可能需要很长时间。

简而言之,如果可能的话,我需要一种方法来获取每个表的大小,因为它一旦被解压缩,并且在呈现给应用程序的等式中会出现碎片。我对不同的方法持开放态度,首选 T-SQL,但我不反对 Powershell 或其他创造性方法。

假设应用程序中的缓冲区是数据的大小。bigint 始终是 bigint 的大小,而字符数据类型是每个字符 2 个字节(unicode)。BLOB 数据也占用数据的大小,枚举基本上是一个整数,数字数据是 numeric(38,12),datetime 是日期时间的大小。此外,没有NULL值,它们要么存储为空字符串,要么存储1900-01-01为零。

没有关于如何实现的文档,但这些假设基于一些测试以及 PFE 和支持团队使用的脚本(显然也忽略了压缩,因为检查是在应用程序中构建的,而应用程序无法分辨)如果底层数据被压缩),它还检查表大小。例如,此链接指出:

避免对大型表使用 EntireTable 缓存(在 AX 2009 中超过 128 KB 或 16 页,在 AX 2012 中超过“整个表缓存大小”应用程序设置[默认值:32KB 或 4 页])——改为使用记录缓存。

sql-server size cache compression

12
推荐指数
2
解决办法
1498
查看次数

访问基于另一个数据库中的表的视图,而无需在该另一个数据库中的帐户

我根据 database2 中的表在 database1 中创建了视图。我SELECT授予了一个只能访问 database1 的用户的权限。用户无法使用此视图,因为他在 database2 中没有帐户。我该如何解决这个问题?我不想在 database2 中创建帐户。

sql-server-2008 security sql-server permissions view

12
推荐指数
1
解决办法
1万
查看次数

如果不打算卸载,是否可以删除 Setup Bootstrap 文件夹中的 Log 和 Update Cache 文件夹?

我的笔记本电脑上安装了多个版本的 SQL Server,用于测试(2012、2014、2016 和 2017)。前几天我注意到有一个文件夹包含跨更新(SP、CU)的文件的先前版本。在所有版本中,实际上占用了相当多的空间:

(在C:\Program Files (x86)\Microsoft SQL Server\ 中)

110\Setup Bootstrap\Log - 91.8 MB (818 files)
110\Setup Bootstrap\Update Cache - 608 MB (2,382 files)
Run Code Online (Sandbox Code Playgroud)

(以下所有文件夹都位于:C:\Program Files\Microsoft SQL Server\)

110\Setup Bootstrap\Log - 1.18 GB (3,715 files)
110\Setup Bootstrap\Update Cache - 9.58 GB (14,766 files)

120\Setup Bootstrap\Log - 569 MB (2,963 files)
120\Setup Bootstrap\Update Cache - 5.74 GB (12,797 files)

130\Setup Bootstrap\Log - 448 MB (2,808 files)
130\Setup Bootstrap\Update Cache - 3.84 GB (8,579 files)

140\Setup …
Run Code Online (Sandbox Code Playgroud)

sql-server best-practices management disk-space

12
推荐指数
1
解决办法
8380
查看次数

如何从 SQL Server 审计数据中过滤掉标量值用户定义函数的使用情况?

我们有一个 SQL Server 数据库,它有一个数据库审计规范,它审计对数据库的所有执行操作。

CREATE DATABASE AUDIT SPECIFICATION [dbAudit]
FOR SERVER AUDIT [servAudit]
ADD (EXECUTE ON DATABASE::[DatabaseName] BY [public])
Run Code Online (Sandbox Code Playgroud)

我们发现,某些查询会将结果集中的每一行的标量函数的使用写入审计日志。当这种情况发生时,日志在我们可以 ETL 到它的最终休息位置之前就被填满了,我们的日志记录出现了空白。

不幸的是,由于合规性原因,我们不能简单地停止审核每条EXECUTE语句。

我们解决这个问题的第一个想法是使用Server AuditWHERE上的子句来过滤掉活动。代码如下所示:

WHERE [object_id] not in (Select object_id from sys.objects where type = 'FN' )
Run Code Online (Sandbox Code Playgroud)

不幸的是,SQL Server 不允许关系 IN 运算符(可能是因为它不想在每次必须写入审核日志时进行查询)。

我们想避免编写一个存储过程,其硬代码object_id中WHERE条款,但是这是我们在解决这个问题的最好办法目前的想法。是否有我们应该考虑的替代方法?

我们注意到,当在递归 CTE 中使用标量函数时,它会导致查询为结果集中的每一行写入审计日志。

有一些标量值函数由供应商提供,我们无法删除或移动到备用数据库。

sql-server audit cte functions recursive

12
推荐指数
1
解决办法
929
查看次数

MS-SQL 上是否有任何(隐藏的)内置函数来取消引用对象名称?

有时我将对象名称(标识符)存储在我们的一些数据库中,例如在一些参数表中。因为我使用 '=' 或 'LIKE' 比较运算符从这些表中选择记录,所以我必须注意存储这些名称时总是带括号或不带括号。

IF EXISTS (SELECT 1 FROM MYTABLE WHERE OBJ_NAME = '[TABLE_NAME]';
Run Code Online (Sandbox Code Playgroud)

或者

IF EXISTS (SELECT 1 FROM MYTABLE WHERE OBJ_NAME = 'TABLE_NAME';
Run Code Online (Sandbox Code Playgroud)

但是,MS-SQL 有一些函数,您可以在其中使用带或不带括号的对象名称,例如 OBJECT_ID() 函数。我在dbfiddle.uk上设置了一个最小的例子。

CREATE TABLE TEST
(
    ID     INT IDENTITY(1,1) PRIMARY KEY,
    OBJECT sysname NOT NULL
);
GO

INSERT INTO TEST VALUES ('[obj1]'),('obj2'),('obj3'),('[obj4]');
GO
Run Code Online (Sandbox Code Playgroud)

现在我可以使用 OBJECT_ID() 以这种方式检查表 TEST 是否存在:

IF OBJECT_ID('TEST') IS NOT NULL
BEGIN
    SELECT 'TEST EXISTS.' OBJECT_ID;
END
GO

| OBJECT_ID    |
| :----------- | …
Run Code Online (Sandbox Code Playgroud)

sql-server t-sql

12
推荐指数
3
解决办法
2351
查看次数

SQL Server 逐行访问

我有一个这样结构的表(简化)

Name, EMail, LastLoggedInAt
Run Code Online (Sandbox Code Playgroud)

我在 SQL Server (RemoteUser) 中有一个用户,该用户应该只能看到 LastLoggdInAt 字段不为空的数据(通过选择查询)。

看起来我可以做到这一点?是否可以?

sql-server row-level-security

12
推荐指数
1
解决办法
982
查看次数

SQL Server 数据库何时准备好接受查询?

在 SQL Server 错误日志文件中,我发现了以下几行:

2018-02-22 14:10:58.95 spid17s     Starting up database 'msdb'.
2018-02-22 14:10:58.95 spid16s     Starting up database 'ReportServer'.
2018-02-22 14:10:58.95 spid18s     Starting up database 'ReportServerTempDB'.
2018-02-22 14:10:58.95 spid19s     Starting up database 'XYZ'.
Run Code Online (Sandbox Code Playgroud)

如果我在此之前检查数据库 XYZ 的状态,则ONLINE使用以下语句:

SELECT state_desc FROM sys.databases WHERE name='XYZ'
Run Code Online (Sandbox Code Playgroud)

...但是当我尝试使用 C# 应用程序连接到该数据库时,它无法连接到该数据库。

错误是:

用户“asd”登录失败。
原因:无法打开明确指定的数据库。

我尝试了三个不同的用户(为应用程序定义的 Windows 用户、sa、SQL Server 用户)。当我在操作系统启动时运行应用程序时会出现问题,但是如果我在启动后手动启动它,则不会发生错误,因此我认为所有 SQL Server 设置和防火墙设置都是正确的。

在此之前,我还检查了服务状态是否正在运行。

我还应该检查什么以确保数据库实际上在线并准备好进行查询?

我正在寻找一个密钥,它告诉我可以查询数据库,而不是延迟一段时间(甚至不是基于明确的原因)。

我想扫描文本“启动数据库'XYZ'”的错误日志,但这意味着我必须为SQL Server错误日志的路径添加应用程序的设置。这也意味着多次阅读文件,直到我找到这句话。

sql-server-2008 sql-server startup

12
推荐指数
1
解决办法
2572
查看次数

以不妨碍并行的方式模拟用户定义的标量函数

我想看看是否有办法欺骗 SQL Server 为查询使用某个计划。

1. 环境

想象一下,您有一些在不同进程之间共享的数据。因此,假设我们有一些占用大量空间的实验结果。然后,对于每个过程,我们知道我们想要使用哪一年/哪月的实验结果。

if object_id('dbo.SharedData') is not null
    drop table SharedData

create table dbo.SharedData (
    experiment_year int,
    experiment_month int,
    rn int,
    calculated_number int,
    primary key (experiment_year, experiment_month, rn)
)
go
Run Code Online (Sandbox Code Playgroud)

现在,对于每个过程,我们都将参数保存在表中

if object_id('dbo.Params') is not null
    drop table dbo.Params

create table dbo.Params (
    session_id int,
    experiment_year int,
    experiment_month int,
    primary key (session_id)
)
go
Run Code Online (Sandbox Code Playgroud)

2. 测试数据

让我们添加一些测试数据:

insert into dbo.Params (session_id, experiment_year, experiment_month)
select 1, 2014, 3 union all
select 2, 2014, 4 
go

insert into …
Run Code Online (Sandbox Code Playgroud)

performance sql-server functions sql-server-2016 query-performance

12
推荐指数
2
解决办法
1003
查看次数

授予 ALTER TABLE 权限有多危险?

想象以下场景

CREATE DATABASE test

GO

USE test;    

CREATE TABLE dbo.Customer
  (
     CustomerId   INT,
     Email        VARCHAR(100),
     SensitiveData VARCHAR(20)
  );

INSERT INTO dbo.Customer
VALUES     (1,'abc@foo.com','12346789');
Run Code Online (Sandbox Code Playgroud)

在某些时候,编写了一个 ETL 过程,在test数据库中执行一些活动。

CREATE USER etlUser WITHOUT LOGIN; /*For demo purposes*/

CREATE TABLE dbo.StagingTable
  (
     StagingTableId INT,
     SomeData       VARCHAR(100),
  )

GRANT UPDATE,INSERT,DELETE,SELECT,ALTER ON dbo.StagingTable TO etlUser;

DENY SELECT ON dbo.Customer TO etlUser;
DENY SELECT ON dbo.Customer (SensitiveData) TO etlUser; /*For good measure*/
Run Code Online (Sandbox Code Playgroud)

etlUser 不应该对Customer表(当然也不是对SensitiveData列)具有权限,因此上面明确拒绝了这些权限。

ETL 过程会截断,dbo.StagingTable因此被授予ALTER表权限。

这在安全审计期间被标记。这个场景有多危险?

sql-server permissions

12
推荐指数
2
解决办法
9161
查看次数