【问题标题】:Hidden Features of SQL ServerSQL Server 的隐藏特性
【发布时间】:2010-09-12 09:12:27
【问题描述】:

SQL Server 有哪些隐藏功能?

例如,未记录的系统存储过程,做一些非常有用但记录不足的事情的技巧?


答案

感谢大家的精彩回答!

存储过程

  • sp_msforeachtable: 运行带有 '?' 的命令替换为每个表名(v6.5 及更高版本)
  • sp_msforeachdb: 运行带有 '?' 的命令替换为每个数据库名称(v7 及更高版本)
  • sp_who2: 与 sp_who 类似,但提供了更多有关块故障排除的信息(v7 及更高版本)
  • sp_helptext:如果要存储过程的代码,查看&UDF
  • sp_tables:返回范围内所有表和数据库视图的列表。
  • sp_stored_procedures:返回所有存储过程的列表
  • xp_sscanf: 将字符串中的数据读取到每个格式参数指定的参数位置。
  • xp_fixeddrives::找到可用空间最大的固定驱动器
  • sp_help:如果你想知道一个表的表结构、索引和约束。还有视图和 UDF。快捷键是 Alt+F1

片段

  • 以随机顺序返回行
  • 最后修改日期的所有数据库用户对象
  • 仅返回日期
  • 查找日期在当前周内的记录。
  • 查找日期为上周的记录。
  • 返回当前星期的开始日期。
  • 返回上周开始的日期。
  • 查看已部署到服务器的过程文本
  • 删除与数据库的所有连接
  • 表校验和
  • 行校验和
  • 删除数据库中的所有过程
  • 恢复后正确重新映射登录 ID
  • 从 INSERT 语句调用存储过程
  • 按关键字查找程序
  • 删除数据库中的所有过程
  • 以编程方式查询数据库的事务日志。

函数

  • HashBytes()
  • EncryptByKey
  • PIVOT 命令

杂项

  • 连接字符串附加功能
  • TableDiff.exe
  • 登录事件触发器(Service Pack 2 中的新增功能)
  • 使用持久计算列 (pcc) 提高性能。
  • sys.database_principles 中的 DEFAULT_SCHEMA 设置
  • 强制参数化
  • Vardecimal 存储格式
  • 在几秒钟内找出最受欢迎的查询
  • 可扩展的共享数据库
  • SQL Management Studio 中的表/存储过程过滤器功能
  • 跟踪标志
  • GO 重复批次后的编号
  • 使用架构的安全性
  • 使用内置加密函数、视图和带有触发器的基表进行加密

【问题讨论】:

  • 如果知道,最好在每个答案中包含适用的版本。 (2000 年及以上,仅 2005 年、2000 年等)
  • 这个问题有很多好处。请不要删除它! :-)

标签: sql-server tsql


【解决方案1】:

在 Management Studio 中,您可以在 GO 批次结束标记之后放置一个数字,以使批次重复该次数:

PRINT 'X'
GO 10

将打印 'X' 10 次。这可以让您在做重复性工作时免于繁琐的复制/粘贴。

【讨论】:

    【解决方案2】:

    许多 SQL Server 开发人员似乎仍然不知道 DELETE、INSERT 和 UPDATE 语句中的 OUTPUT clause(SQL Server 2005 及更高版本)。

    知道哪些行已被插入、更新或删除是非常有用的,并且 OUTPUT 子句允许非常容易地做到这一点 - 它允许访问名为 inserted 和 deleted 的“虚拟”表(就像在触发器中一样):

    DELETE FROM (table)
    OUTPUT deleted.ID, deleted.Description
    WHERE (condition)
    

    如果您将值插入到具有 INT IDENTITY 主键字段的表中,使用 OUTPUT 子句,您可以立即获取插入的新 ID:

    INSERT INTO MyTable(Field1, Field2)
    OUTPUT inserted.ID
    VALUES (Value1, Value2)
    

    如果您正在更新,了解发生了什么变化非常有用 - 在这种情况下,inserted 代表新值(更新之后),而deleted 指的是更新之前的旧值:

    UPDATE (table)
    SET field1 = value1, field2 = value2
    OUTPUT inserted.ID, deleted.field1, inserted.field1
    WHERE (condition)
    

    如果会返回很多信息,也可以将 OUTPUT 的输出重定向到临时表或表变量(OUTPUT INTO @myInfoTable)。

    非常有用 - 但鲜为人知!

    马克

    【讨论】:

      【解决方案3】:

      sp_msforeachtable: 运行带有 '?' 的命令替换为每个表名。 例如

      exec sp_msforeachtable "dbcc dbreindex('?')"
      

      每个表最多可以发出 3 个命令

      exec sp_msforeachtable
          @Command1 = 'print ''reindexing table ?''',
          @Command2 = 'dbcc dbreindex(''?'')',
          @Command3 = 'select count (*) [?] from ?'
      

      另外,sp_MSforeachdb

      【讨论】:

      • 可以通过在问号两边加上单引号来获取查询中的表名。 sp_msforeachtable“选择计数(*),'?'作为 tabenm 来自 ?"
      【解决方案4】:

      连接字符串附加功能:

      MultipleActiveResultSets=true;

      这使得 ADO.Net 2.0 及更高版本在单个数据库连接上读取多个、只进、只读的结果集,如果您进行大量读取,这可以提高性能。即使您正在执行多种查询类型,也可以将其打开。

      应用程序名称=MyProgramName

      现在,当您想通过查询 sysprocesses 表来查看活动连接列表时,您的程序名称将出现在 program_name 列中,而不是“.Net SqlClient Data Provider”

      【讨论】:

      • 我的公司要求应用程序名称。每个新应用程序都必须有一个唯一的名称。更容易追踪哪个应用程序锁定/破坏了某些东西。
      • 应用程序名称也可用作分析器中的过滤器。如果您只想查看自己的查询而不是同事的查询,这会很有帮助。
      【解决方案5】:

      TableDiff.exe

      • 表差异工具允许您发现和协调源表和目标表或视图之间的差异。 Tablediff 实用程序可以报告模式和数据的差异。 tablediff 最受欢迎的功能是它可以生成一个脚本,您可以在目标上运行该脚本来协调表之间的差异。

      Link

      【讨论】:

        【解决方案6】:

        一种鲜为人知的以随机顺序返回行的 TSQL 技术:

        -- Return rows in a random order
        SELECT 
            SomeColumn 
        FROM 
            SomeTable
        ORDER BY 
            CHECKSUM(NEWID())
        

        【讨论】:

        • 非常适合小型结果集。除非您有空闲时间,否则我不会在超过 10000 行的表上使用它
        • 我在比这大得多的桌子上使用过它,而且速度不算太慢。
        • CHECKSUM() 的目的是什么?您可以通过 NEWID() 订购。
        • 我什至在 100,000,000(1 亿)行上看到了不错的结果,没有 CHECKSUM()。另外,我还要问,为什么不直接 ORDER BY NEWID 呢?
        • @GateKiller:我已经回滚了你的编辑,因为 Checksum() 不是错误;它减小了排序列的大小。
        【解决方案7】:

        在 Management Studio 中,您可以通过以下方式快速获取以逗号分隔的表格列列表:

        1. 在对象资源管理器中,展开给定表下的节点(这样您将看到列、键、约束、触发器等文件夹)
        2. 指向列文件夹并拖入查询。

        当您不想使用通过右键单击表并选择 Script Table As...,然后选择 Insert To... 返回的令人发指的格式时,这很方便。这个技巧适用于其他文件夹,因为它将为您提供文件夹中包含的名称的逗号分隔列表。

        【讨论】:

          【解决方案8】:

          行构造函数

          您可以使用单个插入语句插入多行数据。

          INSERT INTO Colors (id, Color)
          VALUES (1, 'Red'),
                 (2, 'Blue'),
                 (3, 'Green'),
                 (4, 'Yellow')
          

          【讨论】:

          • 我投了赞成票,但后来在 MSSQL 2005 中尝试了它,但它不起作用。仅限 2008 年?
          • 是的,这是 2008 年的新功能。
          • 这是我从 DB2 转向 SQL Server 时错过的一个特性。在 DB2 中,当使用 this 而不是单独的插入语句时,速度显着提高
          【解决方案9】:

          如果你想知道表结构、索引和约束:

          sp_help 'TableName'
          

          【讨论】:

          • 把这个技巧和它的快捷键结合起来!首先突出显示一个表名,然后按 ALT+F1
          【解决方案10】:

          HashBytes() 返回其输入的 MD2、MD4、MD5、SHA 或 SHA1 哈希。

          【讨论】:

          【解决方案11】:

          找出最热门的查询

          • 使用 sys.dm_exec_query_stats,您可以通过单个查询找出多种查询分析组合。

          Link 用命令

          select * from sys.dm_exec_query_stats 
          order by execution_count desc
          

          【讨论】:

            【解决方案12】:

            【讨论】:

            • 我在查询结果中看到了耶稣!
            • Pfff... 什么笨蛋浪费时间来搞乱空间结果选项卡。哦等等……你知道,我觉得那个帖子看起来很眼熟,现在我想起来了。
            【解决方案13】:

            EXCEPT and INTERSECT

            在比较两个查询结果时,这两个关键字不是编写复杂的连接和子查询,而是一种更优雅的速记和可读性表达查询意图的方式。自 SQL Server 2005 起新增,它们有力地补充了 TSQL 语言中已存在多年的 UNION。

            EXCEPT、INTERSECT 和 UNION 的概念是集合论的基础,集合论是所有现代 RDBMS 使用的关系建模的基础。现在,使用 TSQL 可以更直观、更轻松地生成维恩图类型结果。

            【讨论】:

              【解决方案14】:

              我知道它并没有完全隐藏,但没有太多人知道​​PIVOT 命令。我能够更改一个使用游标的存储过程,并在 2 分钟内运行了一段 6 秒的快速代码,该代码是行数的十分之一!

              【讨论】:

                【解决方案15】:

                在为测试目的或其他目的恢复数据库时很有用。正确重新映射登录 ID:

                EXEC sp_change_users_login 'Auto_Fix', 'Mary', NULL, 'B3r12-36'
                

                【讨论】:

                • 我之前有过这个过程不起作用,我不得不将对象所有权更改为临时用户,删除原始用户,重新添加原始用户并重新分配所有权。呃……
                【解决方案16】:

                删除与数据库的所有连接:

                Use Master
                Go
                
                Declare @dbname sysname
                
                Set @dbname = 'name of database you want to drop connections from'
                
                Declare @spid int
                Select @spid = min(spid) from master.dbo.sysprocesses
                where dbid = db_id(@dbname)
                While @spid Is Not Null
                Begin
                        Execute ('Kill ' + @spid)
                        Select @spid = min(spid) from master.dbo.sysprocesses
                        where dbid = db_id(@dbname) and spid > @spid
                End
                

                【讨论】:

                • 是否有一个单行或删除数据库参数可以为我执行此操作?我注意到,如果您尝试通过用户界面“删除数据库”,则会有一个“关闭现有连接”复选框,这意味着它是一个布尔参数。
                • 其实我只是找到了一个两行的解决方案。 ALTER DATABASE [@DATABASE_NAME@] SET READ_ONLY WITH ROLLBACK IMMEDIATE -- 这会断开所有用户的连接 ALTER DATABASE [@DATABASE_NAME@] SET READ_WRITE WITH ROLLBACK IMMEDIATE DROP DATABASE [@DATABASE_NAME@]
                • ALTER DATABASE MyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE 也会阻止任何新连接的发生。
                【解决方案17】:

                表校验和

                Select CheckSum_Agg(Binary_CheckSum(*)) From Table With (NOLOCK)
                

                行校验和

                Select CheckSum_Agg(Binary_CheckSum(*)) From Table With (NOLOCK) Where Column = Value
                

                【讨论】:

                • 这些允许您为表中的所有数据生成校验和。这是检查两行或两个表是否相同的一种简单快捷的方法。
                【解决方案18】:

                我不确定这是否是一个隐藏功能,但我偶然发现了这一点,并发现它在许多场合都很有用。您可以在单个 select 语句中连接一组字段,而不是使用游标并循环通过 select 语句。

                例子:

                DECLARE @nvcConcatonated nvarchar(max)
                SET @nvcConcatonated = ''
                
                SELECT @nvcConcatonated = @nvcConcatonated + C.CompanyName + ', '
                FROM tblCompany C
                WHERE C.CompanyID IN (1,2,3)
                
                SELECT @nvcConcatonated
                

                结果:

                Acme, Microsoft, Apple,
                

                【讨论】:

                • 你也可以使用 COALESCE() 来做同样的事情,而不需要初始化变量。 SELECT @nvcConcatonated = COALESCE(@nvcConcatonated+',','')+CAST(C.CompanyName as VARCHAR(255)) FROM...
                • 这也适用于更新语句。有时对于连接已更新的 ID 列表等操作很有用。
                【解决方案19】:

                如果你想要存储过程的代码,你可以:

                sp_helptext 'ProcedureName'
                

                (不知道是不是隐藏功能,但我一直都在用)

                【讨论】:

                • 不知道为什么,但是 sp_helptext 的输出在原始文件中的任何过长的行上都有点愚蠢。在编写 Sproc 脚本时,这不会发生,所以也许还有另一种更强大的导出机制? sp_helptext 'MyView' 也很有用。
                • 我不确定你的意思。对我来说,SP 代码的输出格式与我在原始文件中编写的脚本相同(包括所有 CR 等)
                • 我不记得确切的细节,但它与文本的存储方式有关——我相信与页面大小有关。输出大部分是正确的,但时不时你会得到一个额外的换行符。
                【解决方案20】:

                存储过程的一个技巧是您可以从 INSERT 语句中调用它们。当我在处理 SQL Server 数据库时,我发现这非常有用。

                CREATE TABLE #toto (v1 int, v2 int, v3 char(4), status char(6))
                INSERT #toto (v1, v2, v3, status) EXEC dbo.sp_fulubulu(sp_param1)
                SELECT * FROM #toto
                DROP TABLE #toto
                

                【讨论】:

                • 遗憾的是不能与@TableVariable 一起使用
                • 这种非常有用的技术的痛苦在于,与大多数#tables 不同,您必须完全定义所有列。这样做的懒惰方法是在最后调用的 proc 中创建#table,然后在 tempdb 中创建 sp_help,复制和粘贴,从 proc 中删除代码。完成
                【解决方案21】:

                在 SQL Server 2005/2008 中显示 SELECT 查询结果中的行号:

                SELECT ( ROW_NUMBER() OVER (ORDER BY OrderId) ) AS RowNumber,
                        GrandTotal, CustomerId, PurchaseDate
                FROM Orders
                

                ORDER BY 是强制性子句。 OVER() 子句告诉 SQL 引擎对指定列(在本例中为 OrderId)上的数据进行排序,并根据排序结果分配数字。

                【讨论】:

                【解决方案22】:

                用于解析存储过程参数:xp_sscanf

                从字符串中读取数据到每个格式参数指定的参数位置。

                以下示例使用 xp_sscanf 从源中提取两个值 字符串基于它们在 源字符串的格式。

                DECLARE @filename varchar (20), @message varchar (20)
                EXEC xp_sscanf 'sync -b -fproducts10.tmp -rrandom', 'sync -b -f%s -r%s', 
                  @filename OUTPUT, @message OUTPUT
                SELECT @filename, @message
                

                这是结果集。

                -------------------- -------------------- 
                products10.tmp        random
                

                【讨论】:

                • 我一定有一个愚蠢的时刻(不,真的)。你能告诉我我们可以在哪里使用它吗?
                【解决方案23】:

                仅返回日期

                Select Cast(Floor(Cast(Getdate() As Float))As Datetime)
                

                或

                Select DateAdd(Day, 0, DateDiff(Day, 0, Getdate()))
                

                【讨论】:

                • 短版 - SELECT CAST(FLOOR(CAST(@DateTime AS FLOAT))AS DATETIME)
                • 见鬼。 CASTFLOORCAST 规则。
                • 找不到对它的引用,但我似乎记得测试表明 SELECT DateAdd(Day, 0, DateDiff(Day, 0, @DateTime)) 更快。不管怎样,很高兴开悟!
                • 找到了这个sqlteam.com/forums/topic.asp?TOPIC_ID=35296#107617,但它不包括 CAST/FLOOR 方法。对中型记录集的非正式测试表明,DATEADD 可能比 CAST/FLOOR 快 7% - 在大多数情况下都不足以担心
                • 不过,我添加了另一种方法;我的快速测试表明,铸造地板方法快 800 纳秒。所以真的什么都没有。
                【解决方案24】:

                dm_db_index_usage_stats

                这可以让您知道表中的数据最近是否已更新,即使表上没有 DateUpdated 列也是如此。

                SELECT OBJECT_NAME(OBJECT_ID) AS DatabaseName, last_user_update,*
                FROM sys.dm_db_index_usage_stats
                WHERE database_id = DB_ID( 'MyDatabase')
                AND OBJECT_ID=OBJECT_ID('MyTable')
                

                代码来自:http://blog.sqlauthority.com/2009/05/09/sql-server-find-last-date-time-updated-for-any-table/

                参考资料来自: SQL Server - What is the date/time of the last inserted row of a table?

                在 SQL 2005 及更高版本中可用

                【讨论】:

                  【解决方案25】:

                  以下是一些我觉得有用但很多人似乎不知道的功能:

                  sp_tables
                  

                  返回一个对象列表 在当前环境中查询。 这意味着任何可以出现的对象 在 FROM 子句中,同义词除外 对象。

                  Link

                  sp_stored_procedures
                  

                  返回存储过程的列表 当前环境。

                  Link

                  【讨论】:

                    【解决方案26】:

                    查找日期在当前周内某处的记录。

                    where dateadd( week, datediff( week, 0, TransDate ), 0 ) =
                    dateadd( week, datediff( week, 0, getdate() ), 0 )
                    

                    查找上周发生日期的记录。

                    where dateadd( week, datediff( week, 0, TransDate ), 0 ) =
                    dateadd( week, datediff( week, 0, getdate() ) - 1, 0 )
                    

                    返回当前星期的开始日期。

                    select dateadd( week, datediff( week, 0, getdate() ), 0 )
                    

                    返回上周开始的日期。

                    select dateadd( week, datediff( week, 0, getdate() ) - 1, 0 )
                    

                    【讨论】:

                    • 很好,但不会使用 TransDate 上的索引。我宁愿写
                    • 其中 TransDate >= convert(datetime, floor(convert(float, dateadd(day, -datepart(weekday, @date)+1, @date)))) 和 TransDate >= convert(datetime , floor(convert(float, dateadd(day, 7-datepart(weekday, @date)+1, @date))))
                    • 更正:其中 TransDate >= convert(datetime, floor(convert(float, dateadd(day, -datepart(weekday, @date)+1, @date)))) 和 TransDate
                    【解决方案27】:

                    与其说是隐藏功能,不如说是在 Management Studio 中的 Tools\Options\Keyboard 下设置键映射: Alt+F1 默认为 sp_help "selected text" 但如果不为 sp_helptext "selected text" 添加 Ctrl+F1 我就活不下去

                    【讨论】:

                    • 我也用来配置 USE 命令,用于沿着 db 移动
                    【解决方案28】:

                    持久计算列

                    • 计算列可以帮助您将运行时计算成本转移到数据修改阶段。计算列与行的其余部分一起存储,并在计算列上的表达式与查询匹配时透明地使用。您还可以在 PCC 上构建索引,以加快表达式的过滤和范围扫描。

                    Link

                    【讨论】:

                      【解决方案29】:

                      有时没有合适的列可供排序,或者您只想在表上使用默认排序顺序并且想要枚举每一行。为了做到这一点,您可以在“order by”子句中放入“(select 1)”,您将得到您想要的。整洁,嗯?

                      select row_number() over (order by (select 1)), * from dbo.Table as t
                      

                      【讨论】:

                        【解决方案30】:

                        使用EncryptByKey进行简单加密

                        【讨论】:

                          猜你喜欢
                          • 2010-11-05
                          • 2011-03-19
                          • 1970-01-01
                          • 1970-01-01
                          • 2010-11-07
                          • 2010-09-15
                          • 2010-11-07
                          • 2010-09-22
                          • 2010-10-31
                          相关资源
                          最近更新 更多