我正在优化一些使用数据库的服务器应用程序任务(查询、复杂计算、数据插入...)。执行此任务花费大约 16 分钟(我已经测试了 3 次以上)并且它是可预测的时间来完成它。
然后我执行了脚本:
ALTER INDEX ALL ON dbo.'+ @TableName +' REBUILD
对于数据库中的每个表。而我现在看到的。我的任务执行时间增加到 24 分钟。如果这些不是对这项任务的任何外部影响,那会发生什么?我在等待性能的提高(由于重建碎片索引)但性能下降。
我正在优化一些使用数据库的服务器应用程序任务(查询、复杂计算、数据插入...)。执行此任务花费大约 16 分钟(我已经测试了 3 次以上)并且它是可预测的时间来完成它。
然后我执行了脚本:
ALTER INDEX ALL ON dbo.'+ @TableName +' REBUILD
对于数据库中的每个表。而我现在看到的。我的任务执行时间增加到 24 分钟。如果这些不是对这项任务的任何外部影响,那会发生什么?我在等待性能的提高(由于重建碎片索引)但性能下降。
我有几个表和应用程序服务,可以密集地插入、更新它。另一方面,一些客户端应用程序必须使用这些表来读取数据。有时客户端应用程序会因为锁定此共享数据而出现超时异常。分离密集修改的数据并快速读取同一数据的常见或非有序解决方案是什么。顺便说一句,数据可以是一致的,但可以在时间上延迟 10-20 秒(例如)。不能使用 OLAP。
我们的开发人员正在处理的数据库太大(有很多数据库对象)。我们必须控制数据库对象的更改(更改管理)。我们公司不能有一个人只负责数据库更改。所以我们需要数据库对象的源代码安全,比如标准代码的版本控制,但与数据库更相关,可以同步数据库和脚本。什么是最好的。可靠、便宜、实用 - 选择这两个 :)
我在我的 Sql Server 上发现了所有错误,我得到了错误:
将数据库上下文更改为“MyDbName”。将语言设置更改为 us_english。
我还没有找到任何关于这个错误的问题和严重性的明确解释。这很关键吗?
我得到了这样的错误:
正在恢复数据库“MyDb”。等到恢复完成。
那个时候我做了一个危急手术。
造成这种情况的原因是什么?又该如何避免呢?
我在一个表(源)上有一个触发器,数据应该被复制到另一个数据库中的另一个(目标)。我正在尝试为数据实现自定义同步过程:我希望目标数据库(表)将是最新的源数据库(表)。我有 300 张表要同步。其中一些具有不同的物理数据结构。由于不同的数据架构和其他限制(实施时间、环境问题...),我无法使用 Sql Server 的标准方法(复制、DTS ...)。我的目标是:此触发器不应影响源表中记录的 INSERT、DELETE、UPDATE。我试过这样的解决方案:
CREATE TRIGGER dbo.MyTrigger
...
AFTER INSERT
....
BEGIN TRY
--RAISERROR('Test error', 16, 2)
END TRY
BEGIN CATCH
-- nothing
END CATCH
我已插入RAISEERROR
以模拟错误。我希望try/catch
抑制该错误并成功插入(删除或更新)记录。不。这没用。我收到错误:
触发器执行期间引发错误。批处理已中止,并且用户事务(如果有)已回滚。
是否有可能以这种方式实现我的解决方案。如何捕获并保持(抑制)触发器中的任何错误?
try/catch
如果它不起作用,在触发器中使用什么意义?
将一个范围 (TSQL) 中的一组数据库(20 个以上)备份到同一文件位置时,我遇到了奇怪的延迟。
是否有可能同时运行多个备份操作?我没有在BACKUP子句中找到任何“WAIT”操作,但是这个选项存在于Backup类的 SMO 命令( Wait)中。
这是我的部分代码(完整代码运行良好,所以我想如下所示进行描述):
WHILE 1 = 1
BEGIN
SET @currentDbName = ...
SET @sql = 'BACKUP DATABASE ' + @currentDbName + '...'
EXEC(@sql)
-- maybe it is a good place to wait?
-- WAITFOR
END
有一个大表(5-6 百万条记录)。我必须将 90% 的旧记录移动到其他数据库(表)。解决方案?
我必须在存储过程中启动循环过程,然后必须在一段时间后(12-24 小时后)停止它。存储过程的工作不应启动两次。SQL Server 客户端(调用方)不应等待且不应执行超时。如何实施?
CREATE PROC dbo.CyclingProcess
AS
BEGIN
/*
.. how to start or stop process by external caller
*/
WHILE(1 = 1)
BEGIN
EXEC mysp_WorkingProcedure -- some working process...
@input1 = @input1
....
,@delay = @delay output
WAITFOR DELAY @delay
END
END
我必须在很长一段时间内做一些重复的工作。我必须开始这个过程并停止它。为什么是存储过程?我必须为 [some work] 更改一些输入参数,并在延迟一段时间后再次调用它。也许你知道其他更聪明的方法来实现它。这个循环过程应该在数据库中工作。
让我们检查一下这两个语句:
IF (CONDITION 1) OR (CONDITION 2)
...
IF (CONDITION 3) AND (CONDITION 4)
...
如果CONDITION 1
是TRUE
,会CONDITION 2
被检查吗?
如果CONDITION 3
是FALSE
,会CONDITION 4
被检查吗?
条件如何WHERE
:SQL Server 引擎是否优化WHERE
子句中的所有条件?程序员是否应该按正确的顺序放置条件以确保 SQL Server 优化器以正确的方式解决它?
添加:
感谢 Jack 的链接,来自 t-sql 代码的惊喜:
IF 1/0 = 1 OR 1 = 1
SELECT 'True' AS result
ELSE
SELECT 'False' AS result
IF 1/0 = 1 AND 1 = 0
SELECT 'True' AS result
ELSE
SELECT 'False' AS result
在这种情况下,不会引发除以零异常。
结论:
如果 C++/C#/VB 有短路,为什么 SQL Server 不能有它?
要真正回答这个问题,让我们来看看两者是如何在条件下工作的。C++/C#/VB 都在语言规范中定义了短路以加速代码执行。为什么要在第一个已经为真时评估 N OR 条件或在第一个已经为假时评估 M AND 条件。
作为开发人员,我们必须意识到 SQL Server 的工作方式不同。这是一个基于成本的系统。为了获得我们查询的最佳执行计划,查询处理器必须评估每个 where 条件并为其分配成本。然后将这些成本作为一个整体进行评估,以形成一个阈值,该阈值必须低于 SQL Server 为一个好的计划而定义的阈值。如果成本低于定义的阈值,则使用计划,如果不是,则使用不同的条件成本组合再次重复整个过程。这里的成本是扫描或查找或合并连接或哈希连接等......因此,C++/C#/VB 中可用的短路是不可能的。您可能认为在列上强制使用索引算作短路,但事实并非如此。它只强制使用该索引,从而缩短可能的执行计划列表。该系统仍然基于成本。
作为开发人员,您必须意识到 SQL Server 不会像在其他编程语言中那样进行短路,并且您无法强制它这样做。
我有一个表,其中字段Id
( bigint
, IDENTITY
) 作为主键和聚簇索引。我插入了 400 行并看到了执行计划。我得到:此插入的相对查询成本为 36%,此查询“聚集索引插入”的成本为 97%。这是怎么回事?为什么它工作这么慢?
添加:
继续
另请参见SQL Server 插入性能
我读过一篇文档(Designing Highly Scalable OLTP Systems),它描述了如何获得更高性能的技巧:
因为行很小(许多适合一页)多个锁可能会争用一个 PAGELATCH。我们可以“浪费”一点空间来获得更多的性能。解决方案:用 CHAR 列填充行,使每一行占据整页。
有人使用这种方法吗?你有什么结果?
谢谢你。
添加:
警告。链接的文章不是行动指南。Thomas Kejser描述了对 TB 大小的数据库的测试,仅此而已。
RDBMS 系统是否针对COMMIT
操作进行了优化?操作的速度有多慢/快ROLLBACK
,为什么?
我的数据库有一个表:tableX。
Task1将密集的 INSERT(每分钟 1000 条记录)作为要处理的记录,并且很少将 UPDATE(每分钟 1-2 条记录)作为要重新计算的记录。
同时其他Task2 SELECT 未处理记录(由 Task1 插入),然后在一个事务中将新记录(已处理)插入同一个 tableX (计算时间太长,最多 10 秒)。
Task3重新计算 UPDATED 记录(通过 Task1):只是 UPDATEs tableX。
有人可以推荐设计以避免这种情况下的长时间锁定和死锁。按插入顺序处理所有 INSERTED 记录非常重要!
1)我应该分开(创建一个新的tableX2)已处理和未处理的记录吗?
2) 我应该在 Task1 中分离事务并在两个单独的事务中执行 SELECT 和 INSERT 吗?
3) 我应该使用 rowlock、readpast...提示以及在哪里(它可以帮助我)吗?
我有这样的表:
语言表中的数据:
等文本表中的数据:
如果请求的语言存在,我必须返回文本;如果默认语言不存在,我必须返回文本。是否可以在一个查询中做到这一点(不while
,请)?
代码:
DECLARE @CommentId bigint = 1
--DECLARE @LanguageCode nvarchar(2) = 'en' -- "english text" returns
DECLARE @LanguageCode nvarchar(2) = 'ua' -- nothing at this moment
SELECT
t.CommentId
,t.TextId
,t.[Text]
,t.LanguageId
,RequestedLanguageId = @LanguageCode
FROM dbo.common_Text t
INNER JOIN dbo.common_LanguageType l
ON t.LanguageId = l.LanguageId
WHERE l.Code = @LanguageCode
AND t.CommentId = @CommentId
谢谢你。
添加:
如果代码请求“ua”(乌克兰语)文本,而这不是该语言的任何文本,那么它将搜索俄语文本。如果找到 - 好的,如果没有找到英文文本。语言列表可能会有所不同。
我有一个表变量:
DECLARE @to_process TABLE
(
[Id] [bigint] NOT NULL,
[SequenceId] [bigint] NOT NULL,
...
)
INSERT INTO @to_process
( Id
, SequenceId
...
)
SELECT
TOP (@recordsToProcess)
Id
, SequenceId
...
在我的存储过程中。我调查过,插入其中大约花费了总执行时间的 66%。
我如何改进或优化我的代码以加速我的 sp 执行?
添加:
我必须使用索引视图来达到性能。正如我从这个比较表中看到的,标准版不支持索引视图。但 BOL 说:
可以在任何版本的 SQL Server 中创建索引视图。在 SQL Server Enterprise 中,查询优化器会自动考虑索引视图。要在所有其他版本中使用索引视图,必须使用 NOEXPAND 表提示。
那么它会起作用吗(我说的是性能)
select * from dbo.OrderTotals with (noexpand, index=IXCU_OrderTotals)
在 SQL Server 标准版上以及它的工作原理
select * from dbo.OrderTotals
在企业一号上?
这是查看代码:
CREATE VIEW dbo.OrderTotals
WITH SCHEMABINDING
AS
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
, XCount = COUNT_BIG(*)
from dbo.Order r
group by r.OrderId
CREATE UNIQUE CLUSTERED INDEX IXCU_OrderTotals ON OrderTotals (OrderId)
我有两个表:这些详细信息的详细信息和总计。
详细信息(慢速解决方案):
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
group by r.OrderId
总计(快速解决方案):
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
有时总数变得无效(某些工作必须重新计算更改的总数,但它会延迟)。正如您所了解的,第二个查询速度更快,并且有效总数比无效总数多。所以我正在寻找一个组合查询,它从第二个表(总计)返回有效总计,并使用第一个慢查询返回动态重新计算的总计。所以我的目标将达到:所有总数都是有效的,响应时间比完全重新计算更快。
这是我的尝试(混合解决方案):
with fast_static(OrderId, TotalQty, TotalGrossConsid, IsValid)
as
(
select
t.OrderId
, t.TotalQty
, t.TotalGrossConsid
, t.IsValid
from dbo.OrderTotal t
)
, slow_dynamic(OrderId, TotalQty, TotalGrossConsid)
(
select
OrderId = r.OrderId
, TotalQty = SUM(r.Quantity)
, TotalGrossConsid = SUM(r.Price * r.Quantity)
from dbo.Order r
)
select
OrderId, TotalQty, TotalGrossConsid
from fast_static
where IsValid = 1
union all
select
OrderId, TotalQty, TotalGrossConsid
from slow_dynamic s
--inner join fast_static ff
--on ff.OrderId = s.OrderId
where --ff.Valid = 0 -- too slow!!!
s.OrderId in (select OrderId from fast_static f where f.Valid = 0)
我比较了快速解决方案和混合解决方案,我得到了 32% 到 68%(相对查询成本)。如果您可以看到注释变体,它等于 1% 到 99%(太糟糕了)。是否可以改进此查询?
添加
@gbn:
Valid = case when i.OrderId is null then 1 else 0 end
...
dbo.OrderTotal t left join dbo.InvalidOrders i
是的,我有一份重新计算总数的工作,这个过程与查询请求不同步。InvalidOrders 表是一个小表,用于存储记录以知道总计无效(要重新计算)
解决方案
索引视图是最佳选择。请注意 SQL Server 版本(非企业版本的noexpand 提示)并准备重新创建一些数据库对象(SET ANSI_NULLS ON, SET QUOTED_IDENTIFIER ON
)以开始在客户端使用索引视图。
在我因为性能问题而尝试避免使用游标之前。但现在我必须做一些计算才能达到一些目标。我有一个存储过程,其代码如下:
DECLARE Outer_Cursor CURSOR FOR...
OPEN Outer_Cursor
FETCH NEXT FROM Outer_Cursor INTO ...
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE Inner_Cursor CURSOR FOR...
OPEN Outer_Cursor
FETCH NEXT FROM Inner_Cursor INTO ...
WHILE @@FETCH_STATUS = 0
BEGIN
...
FETCH NEXT FROM Inner_Cursor INTO ...
END
CLOSE Inner_Cursor
DEALLOCATE Inner_Cursor
FETCH NEXT FROM Outer_Cursor INTO ...
END
CLOSE Outer_Cursor
DEALLOCATE Outer_Cursor
我的问题是:是否有可能避免(最小化)内部光标如此昂贵的光标重建。如何重用内部游标声明,可能吗?
谢谢你。
当我要创建一些时间戳字段(或其他日期/时间样式字段)时,命名它们的最佳方式是什么?我应该只放record_timestamp吗?