AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 164254
Accepted
Magier
Magier
Asked: 2017-02-15 02:20:54 +0800 CST2017-02-15 02:20:54 +0800 CST 2017-02-15 02:20:54 +0800 CST

由于缺少类型长度,缓存中的冗余计划

  • 772

今天我意识到我们的 sql server 的计划缓存中塞满了 hundreads 和数千个几乎相同的编译计划。

在消耗约 4500 MB 的实时系统上,计划总数约为 30.000。看着它们,有数千个几乎相同。

一些样本:

(@ID uniqueidentifier,@GSS nvarchar(663))UPDATE [TAB1] SET [GSS]=@GSS WHERE [ID]=@ID
(@ID uniqueidentifier,@GSS nvarchar(664))UPDATE [TAB1] SET [GSS]=@GSS WHERE [ID]=@ID
(@ID uniqueidentifier,@GSS nvarchar(665))UPDATE [TAB1] SET [GSS]=@GSS WHERE [ID]=@ID
(@ID uniqueidentifier,@GSS nvarchar(666))UPDATE [TAB1] SET [GSS]=@GSS WHERE [ID]=@ID
(@ID uniqueidentifier,@GSS nvarchar(669))UPDATE [TAB1] SET [GSS]=@GSS WHERE [ID]=@ID

(@ID uniqueidentifier,@FR ntext,@uiStamp datetime,@uiUser varchar(10))UPDATE [TTR] SET [FR]=@FR, [uiStamp]=@uiStamp, [uiUser]=@uiUser WHERE [ID]=@ID
(@ID uniqueidentifier,@FR ntext,@uiStamp datetime,@uiUser varchar(11))UPDATE [TTR] SET [FR]=@FR, [uiStamp]=@uiStamp, [uiUser]=@uiUser WHERE [ID]=@ID
(@ID uniqueidentifier,@FR ntext,@uiStamp datetime,@uiUser varchar(12))UPDATE [TTR] SET [FR]=@FR, [uiStamp]=@uiStamp, [uiUser]=@uiUser WHERE [ID]=@ID
(@ID uniqueidentifier,@FR ntext,@uiStamp datetime,@uiUser varchar(13))UPDATE [TTR] SET [FR]=@FR, [uiStamp]=@uiStamp, [uiUser]=@uiUser WHERE [ID]=@ID

该应用程序几乎在任何地方都使用sp_executesql并将值作为参数传递,这就是为什么我确信计划得到重用的原因。

但现在看起来该应用程序根本不关心字符串类型的长度,长度会根据值的实际长度自动添加,从而导致每个传递的字符串值的每个字符串长度组合都有不同的计划。所以大多数情况下,UPDATE 和 INSERT 语句似乎是这里的问题所在。我想一些开发人员在这一点上已经节省了一些时间,只是简单地忽略了大小。

这些冗余 UPDATE/INSERT 类型的计划的使用次数相对较少(通常为 1 次,有的高达 10 次,只有少数高达 40 次)。

它们的大小介于 0.05 MB 和 2 MB 之间。很难说出可能节省的确切值和数量,因为语句之间的长度常量不断变化,因此无法正确排序。但是,我认为这里的平均计划大小在大约 15000 个更新/插入计划中是 0.17 MB,我猜至少可以节省 80%,大概是实际使用的 2550 MB 中的 2040 MB 的潜在节省那15000个计划。这会将总计划缓存使用量从 4500 MB 减少到……。大约 2500 MB。

看起来我们可以很容易地在这里节省一些内存,对吧?

我们谈论的是内存不多 (32 GB) 的 sql server,它们确实可以从一些额外的可用内存中获益,但是,我想这也是一般系统健康状况的问题。

所以我的问题是,我能做些什么呢?我在数据库端有任何选项来控制这个吗?是否有任何我还不知道的临时查询优化选项让我们忽略这个?

还是真的需要开发者在输入参数中正确添加type和typelength?

在 (n)varchar 类型的情况下,表定义中已经定义了前导长度,那么使用这些类型有什么缺点吗?

附加信息:

与此同时,我发现K.Tripps关于计划缓存变得疯狂的帖子......她的查询显示我有 1500 MB 和 20300 个计划,缓存中的使用计数为 1......

在我的特定情况下,“针对临时工作负载进行优化”是灵丹妙药吗?

更多信息: 我发现查询是由 SqlDataAdapter 和 SqlCommandBuilder 创建的。commandbuilder 无论如何都不会从原始表中导出所有已创建参数的参数大小。如果未设置它们,则传入我们的实际值的大小将用作大小值。这可以在此处找到:“如果未明确设置,则根据指定参数值的实际大小推断大小。 ”

sql-server sql-server-2008-r2
  • 2 2 个回答
  • 115 Views

2 个回答

  • Voted
  1. Scott Hodgin - Retired
    2017-02-15T04:02:12+08:002017-02-15T04:02:12+08:00

    查看计划缓存、临时工作负载和清除一次性计划缓存膨胀。

    总结一下:

    • 如果您运行的是 SQL Server 2008 并且缓存被一次性计划浪费,请务必使用新的“针对临时工作负载进行优化”。
    • 如果您仍然发现您浪费了 100 MB 或 GB 的缓存,请考虑创建一个以编程方式检查缓存的作业,然后根据下面的选项/代码之一从缓存中清除“SQL 计划”。

    选项 1 -仅根据 Adhoc/Prepared 一次性计划的数量清除“SQL 计划” ( 2005/2008 ):

    DECLARE @MB DECIMAL(19, 3)
        ,@Count BIGINT
        ,@StrMB NVARCHAR(20)
    
    SELECT @MB = sum(cast((
                    CASE 
                        WHEN usecounts = 1
                            AND objtype IN (
                                'Adhoc'
                                ,'Prepared'
                                )
                            THEN size_in_bytes
                        ELSE 0
                        END
                    ) AS DECIMAL(12, 2))) / 1024 / 1024
        ,@Count = sum(CASE 
                WHEN usecounts = 1
                    AND objtype IN (
                        'Adhoc'
                        ,'Prepared'
                        )
                    THEN 1
                ELSE 0
                END)
        ,@StrMB = convert(NVARCHAR(20), @MB)
    FROM sys.dm_exec_cached_plans
    
    IF @MB > 10
    BEGIN
        DBCC FREESYSTEMCACHE ('SQL Plans')
    
        RAISERROR (
                '%s MB was allocated to single-use plan cache. Single-use plans have been cleared.'
                ,10
                ,1
                ,@StrMB
                )
    END
    ELSE
    BEGIN
        RAISERROR (
                'Only %s MB is allocated to single-use plan cache – no need to clear cache now.'
                ,10
                ,1
                ,@StrMB
                ) —
    
        Note: this IS ONLY a warning message
            AND NOT an actual error.
    END
    GO
    

    选项 2 -

    根据一次性计划浪费的总量清除所有缓存(2005/2008):

    DECLARE @MB DECIMAL(19, 3)
        ,@Count BIGINT
        ,@StrMB NVARCHAR(20)
    
    SELECT @MB = sum(cast((
                    CASE 
                        WHEN usecounts = 1
                            THEN size_in_bytes
                        ELSE 0
                        END
                    ) AS DECIMAL(12, 2))) / 1024 / 1024
        ,@Count = sum(CASE 
                WHEN usecounts = 1
                    THEN 1
                ELSE 0
                END)
        ,@StrMB = convert(NVARCHAR(20), @MB)
    FROM sys.dm_exec_cached_plans
    
    IF @MB > 1000
        DBCC FREEPROCCACHE
    ELSE
        RAISERROR (
                'Only %s MB is allocated to single-use plan cache – no need to clear cache now.'
                ,10
                ,1
                ,@StrMB
                )
    GO
    
    • 1
  2. Best Answer
    Magier
    2017-03-21T02:59:45+08:002017-03-21T02:59:45+08:00

    我们结束了更改应用程序代码。无法避免生成的 Sql 语句中的动态字符长度,以通过 sql server 的配置来保存额外执行计划的创建和存储。所以我们所做的是从命令构建器创建语句的数据集中读取源表的架构。

        SqlCommandBuilder cb = new sqlCommandBuilder(mydataAdapter);
        var schemaDT = new DataTable();
        mydataAdapter.FillSchema(schemaDT, SchemaType.Source);
    

    这样就可以通过将 SqlParameter.SourceColumn 属性与 schemaDT[SqlParameter.SourceColumn] 匹配来为每个参数获取正确的 SqlParameter.Size 属性。

    • 0

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve