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 / 问题 / 232698
Accepted
Learning_DBAdmin
Learning_DBAdmin
Asked: 2019-03-22 01:11:23 +0800 CST2019-03-22 01:11:23 +0800 CST 2019-03-22 01:11:23 +0800 CST

性能改进在生产中出错,在测试中运行良好

  • 772

我们有一个供应商支持的应用程序,并且有一段代码在过程中进行非常繁重的逻辑读取和耗时,因此我建议他们稍微调整查询以减少 IO 和时间,它在在数据和性能方面进行测试,但是它在生产中失败并返回不同的数据,我们不得不回滚更改。需要您的专家建议。

这已经在测试环境中对数据进行了 3 个多月的测试,我们从未遇到任何数据问题。部署后立即开始在生产中出现少量故障,并产生不一致的数据。

现有查询:

SELECT @Ref= CAST(MAX(ISNULL(CAST(ref_clnt AS INT),0))+1 AS VARCHAR(10)) 
FROM table_name WITH(NOLOCK) 
WHERE s_mode='value'

建议查询:

SELECT @Ref = ref_clnt+1 FROM table_name WITH(NOLOCK) 
WHERE RefNo = (SELECT MAX(RefNo) FROM table_name WHERE s_mode = 'value')

表的DDL如下:

CREATE TABLE [dbo].[table_name](
    [RefNo] [dbo].[udt_RefNo] NOT NULL,
    [S_Mode] [varchar](10) NOT NULL,
    [ref_clnt] [varchar](50) NULL)
CONSTRAINT [PK_table_name] PRIMARY KEY CLUSTERED 
(
    [RefNo] ASC
)

仅提供查询中使用的定义中的那些列。

Udt_RefNo是用户定义的数据类型:

CREATE TYPE [dbo].[udt_RefNo] FROM [char](16) NOT NULL
GO

SQL Server 版本:Microsoft SQL Server 2014 (SP3) 版权所有 (c) Microsoft Corporation 企业版(64 位)。

非聚集索引覆盖列如下图:

CREATE NONCLUSTERED INDEX [ncidx_table_name_1] ON [dbo].[table_name]
(
    [S_Mode] ASC,
    [S_Status] ASC
)
INCLUDE (   [ref_clnt])

请按要求查找查询计划:

  • 上一个查询

  • 建议查询

执行计划 开启统计IO和时间后的Reads Number of Reads对比:

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

(1 row affected)
Table 'table_name'. Scan count 1, logical reads 2732, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 157 ms,  elapsed time = 161 ms.

(1 row affected)
Table 'table_name'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

供应商已返回建议作为

SELECT MAX(ISNULL(ref_clnt,0))+1 FROM table_name WITH(NOLOCK) WHERE S_Mode='value'

问题是——如何测试它们,因为它们似乎都适用于大多数情况,但仅在少数情况下失败。我不太了解该应用程序及其供应商支持的应用程序,因此无法获得太多细节,例如业务逻辑如何为底层过程工作。

sql-server sql-server-2014
  • 2 2 个回答
  • 199 Views

2 个回答

  • Voted
  1. Best Answer
    Paul White
    2019-03-22T14:00:54+08:002019-03-22T14:00:54+08:00

    您的重写与原始查询不具有相同的语义,因此不同的结果并不奇怪。

    这是真的,无需担心NOLOCK提示,即使(以某种方式)保证最高ref_clnt值与具有最高RefNo值的行相关联。请参阅此 db<>fiddle 示例。

    与计算机打交道时,精度很重要,因此您需要仔细考虑数据类型和边缘情况。最大RefNo计算将使用字符串排序语义,因此 '999' 的排序高于 '1000'。查询之间还有其他几个重要的区别。我不打算列出所有这些,但NULL处理是另一个例子。

    两个版本的代码中也存在许多错误。ref_clnt如果返回任何 -1000000000 或更低的值,原始文件将失败,因为它不适合varchar(10). 符号使长度为 11。

    安全改进原始版本代码的最简单方法是在计算列上添加索引:

    ALTER TABLE dbo.table_name 
    ADD ref_cc AS 
        ISNULL(CAST(ref_clnt AS integer), 0);
    
    CREATE NONCLUSTERED INDEX i 
    ON dbo.table_name (S_Mode, ref_cc);
    

    数据库<>小提琴演示

    然后执行计划可以直接查找ref_clnt给定值的最高行(按整数排序)S_Mode:

    执行计划

    供应商的原始 SQL 的质量可能仍然值得商榷,但至少它会运行得更快并产生相同的结果。


    供应商的新建议:

    SELECT MAX(ISNULL(ref_clnt,0))+1 FROM table_name WITH(NOLOCK) WHERE S_Mode='value'
    

    ...仍然有问题,至少在理论上是这样,因为ISNULL使用第一个参数的数据类型,所以整数文字0被隐式转换为varchar(50).

    如果不为NULL,则返回check_expression的值;否则,如果类型不同, replacement_value在隐式转换为check_expression的类型后返回。如果replacement_value比check_expression长,则可以截断replacement_value。

    仍然对MAX字符串进行操作,这可能会产生意想不到的结果。在任何情况下,如果没有(不同的)计算列索引,表达式仍然不可搜索。

    • 7
  2. JoeDBA_HAHAHA
    2019-03-22T06:14:26+08:002019-03-22T06:14:26+08:00

    我猜@Ref是varchar(10)。Ref_clnt是varchar(50),你正在向它添加一个。

    SELECT @Ref = ref_clnt+1
    

    ...将生成隐式转换。

    我已将此问题作为警告显示在执行计划中,它影响了我们应用程序的性能。我见过的大多数情况都是这样使用 coalesce 语句的:

    coalesce(field_name, 0) = 0 
    

    应该是什么时候:

    coalesce(field_name, '0') = '0' or coalesce(field_name, '') = ''
    

    ...因为field_name是varchar。

    • 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