zoukankan      html  css  js  c++  java
  • 数据库优化之MS SqlServer篇

    1)在查询中禁用SELECT * FROM Table,需要什么字段选择什么字段

    Ø  避免键查找

    Ø  避免查询到不需要的大字段类型数据,减少网络流量

    SELECT  *FROM dbo.TA_Logistics

    WHERE Col_003='00000000054'

     

    SELECT Col_006 FROM dbo.TA_Logistics

    WHERE Col_003='00000000054'

     

    2)语句带WHERE子句

    需要什么数据就查询、删除、更新什么数据,避免删除、更新出错

    同时能减少SELECT返回的行数,减少网络流量

    3)减少访问数据库的次数

    程序设计中最好将一些常用的配置表加载到内存中或者用其他的方式减少数据库的访问次数,避免使用一次就去连接数据库,减少数据库的负载

    4)不要写一些没有意义的查询

    构建表结构,类似这样的语句可以在代码里面去构建表结构,没必要到服务器查询

    SELECT COL_004,COL_005 FROM TA_Logistics WHERE 1<>1

     

    sys_guid不为空

    当能预知查询没有结果的时候,在客户端就处理掉

     

    declare @P0001 nvarchar(54)

    set @P0001 = N'SELECT doc_path FROM TA_Documents WHERE sys_guid=@arg0'

    declare @P0002 nvarchar(20)

    set @P0002 = N'@arg0 nvarchar(4000)'

    declare @P0003 nvarchar(1)

    set @P0003 = N''

    exec sp_executesql @P0001, @P0002, @arg0 = @P0003

    5)尽量少做重复的工作

    更新一条SQL语句,分两次执行,数据库会记录两次日志

    UPDATE dbo.TA_Logistics SET COL_005='1'

    WHERE Col_003='02700098207'

     

    UPDATE dbo.TA_Logistics SET COL_006='2'

    WHERE Col_003='02700098207'

    这两个语句应该合并成以下一个语句
    UPDATE dbo.TA_Logistics SET COL_005='1' , COL_006='2'

    WHERE Col_003='02700098207'

    6)简化SQL语句,语句关联不要写的太复杂,关联表太多的时候可以使用临时表来保存中间结果

    让查询分析器能正确解析优化SQL语句

    declare @P0001 nvarchar(392)

    set @P0001 = N'Select Col_002,Col_012,Col_014,Col_039,Col_054,Col_006,Col_051,Col_052,Col_008,Col_011,Col_113,Col_119,Col_019

           ,Col_030,Col_065,Col_024,B.DD_133

        from TA_LogisticsPH PH

        LEFT JOIN dbo.TA_LogisticsXD AS B ON B.DD_102 = PH.Col_028 AND B.DD_122 = N''取货''  

        where Col_002=@arg0 or EXISTS(SELECT 1 FROM TA_Logistics YM WHERE PH.lyd_guid = YM.sys_guid AND YM.Col_003 = @arg0)'

    declare @P0002 nvarchar(18)

    set @P0002 = N'@arg0 nvarchar(11)'

    declare @P0003 nvarchar(11)

    set @P0003 = N'76901644328'

    exec sp_executesql @P0001, @P0002, @arg0 = @P0003

     

    正确写法

    declare @P0001 nvarchar(2000)

    set @P0001 = N'Select Col_002,Col_012,Col_014,Col_039,Col_054,Col_006,Col_051,Col_052,Col_008,Col_011,Col_113,Col_119,Col_019 ,Col_030,Col_065,Col_024,B.DD_133

        from TA_LogisticsPH PH

        LEFT JOIN dbo.TA_LogisticsXD AS B ON B.DD_102 = PH.Col_028 AND B.DD_122 = N''取货''  

        where Col_002=@arg0

             UNION

             Select       Col_002,Col_012,Col_014,Col_039,Col_054,Col_006,Col_051,Col_052,Col_008,Col_011,Col_113,C         ol_119,Col_019 ,Col_030,Col_065,Col_024,B.DD_133

        from TA_LogisticsPH PH

        LEFT JOIN dbo.TA_LogisticsXD AS B ON B.DD_102 = PH.Col_028 AND B.DD_122 = N''取货''  

        WHERE EXISTS(SELECT 1 FROM TA_Logistics YM WHERE PH.lyd_guid = YM.sys_guid AND YM.Col_003 = @arg0)'

    declare @P0002 nvarchar(18)

    set @P0002 = N'@arg0 nvarchar(11)'

    declare @P0003 nvarchar(11)

    set @P0003 = N'76901644328'

    exec sp_executesql @P0001, @P0002, @arg0 = @P0003

     

    7)、正确使用ISNULL函数

    使用 ISNULL(字段,'')<>'' 字段<>''效果是一样的

    SELECT  *

    FROM    TV_LogisticsPH

    WHERE   Col_015 >= DATEADD(MONTH, -1, GETDATE())

            AND ISNULL(Col_002, '') = ''

            AND ISNULL(Col_020, '') = ''

            AND Col_090 LIKE N'%'

            AND Col_049 LIKE N'%'

            AND Col_191 IS NULL

            AND EXISTS ( SELECT 1

                         FROM   TV_LogisticsXD AS T2

                         WHERE  Col_028 = T2.DD_102

                                AND DATEDIFF(Mi, ISNULL(DD_120, '2000-01-01'),

                                             GETDATE()) > 20

                                AND ISNULL(DD_120, '2000-01-01') > '2000-01-02' )

            AND NOT EXISTS ( SELECT Col_002

                             FROM   TA_LogisticsXDRemark AS T1

                             WHERE  DATEDIFF(Mi, T1.Col_005, GETDATE()) < 20

                                    AND Col_028 = T1.Col_002 )

            AND ISNULL(Col_020, N'') = N''

            AND NOT EXISTS ( SELECT TOP ( 1 )

                                    1

                             FROM   TA_LogisticsXDRemark T

                             WHERE  T.Col_002 = Col_028

                                    AND CHARINDEX(N'预计',

                                                  SUBSTRING(T.Col_003, 6, 3)) > 0

                             ORDER BY T.Col_005 DESC );

    8)、索引的用法

    不要对索引列计算、转换

    时间字段索引示例

    错误用法

    SELECT

             Z.[Col_D406]

                       ,Z.[Col_D402]

                       ,Z.[Col_D404]

     

    FROM [dbo].[TA_ZWFixedAssetsNewSetDetail4] Z

    WHERE  CONVERT(VARCHAR(7), [Col_D404], 120) = N'2017-03'

    正确用法

    SELECT

             Z.[Col_D406]

                       ,Z.[Col_D402]

                       ,Z.[Col_D404]

     

    FROM [dbo].[TA_ZWFixedAssetsNewSetDetail4] Z

    WHERE  [Col_D404]>='2017-03-01' AND [Col_D404]<N'2017-04-01'

    9)、正确使用字符集

    数据集的转换只用两个表的字段字符集不一致才需要

    错误用法

    UPDATE  dbo.TA_Logistics

    SET     Col_306 = ( CASE WHEN ISNULL(Col_334, 0) = 0

                                  AND ISNULL(Col_349, '') = ''

                             THEN ( ( ISNULL(YD.Col_018, 0) - ISNULL(YD.Col_083, 0)

                                      - ISNULL(YD.Col_032, 0) )

                                    * ISNULL(CASE WHEN ISNULL(D.DriverNa, '') = ''

                                                  THEN D2.DriverRate

                                                  ELSE D.DriverRate

                                             END, 0) / 100.0 )

                             ELSE Col_306

                        END ) ,

            Col_297 = CASE WHEN ISNULL(D.DriverNa, '') = '' THEN D2.DriverNa

                           ELSE D.DriverNa

                      END ,

            Col_298 = CASE WHEN ISNULL(D.DriverNa, '') = '' THEN D2.DriverRate

                           ELSE D.DriverRate

                      END

    FROM    dbo.TA_Logistics AS YD

            LEFT JOIN dbo.TB_CompanyJJ AS D ON YD.Col_117 = D.Company COLLATE Chinese_PRC_CI_AS

            LEFT JOIN dbo.TB_CompanyJJ AS D2 ON YD.Col_043 = D2.Company COLLATE Chinese_PRC_CI_AS

    WHERE   YD.sys_guid IN ( '4C8033A912254779B9ABC37D3A4886C7',

                             '8365C38506AB4FEA8D453A531D85B360' );

     

    正确用法

    UPDATE  dbo.TA_Logistics

    SET     Col_306 = ( CASE WHEN ISNULL(Col_334, 0) = 0

                                  AND ISNULL(Col_349, '') = ''

                             THEN ( ( ISNULL(YD.Col_018, 0) - ISNULL(YD.Col_083, 0)

                                      - ISNULL(YD.Col_032, 0) )

                                    * ISNULL(CASE WHEN ISNULL(D.DriverNa, '') = ''

                                                  THEN D2.DriverRate

                                                  ELSE D.DriverRate

                                             END, 0) / 100.0 )

                             ELSE Col_306

                        END ) ,

            Col_297 = CASE WHEN ISNULL(D.DriverNa, '') = '' THEN D2.DriverNa

                           ELSE D.DriverNa

                      END ,

            Col_298 = CASE WHEN ISNULL(D.DriverNa, '') = '' THEN D2.DriverRate

                           ELSE D.DriverRate

                      END

    FROM    dbo.TA_Logistics AS YD

            LEFT JOIN dbo.TB_CompanyJJ AS D ON YD.Col_117 = D.Company

            LEFT JOIN dbo.TB_CompanyJJ AS D2 ON YD.Col_043 = D2.Company

    WHERE   YD.sys_guid IN ( '4C8033A912254779B9ABC37D3A4886C7',

                             '8365C38506AB4FEA8D453A531D85B360' );

    10尽量避免大事务操作,提高系统并发能力

     

    针对需要大量更新数据的事务,需要将每次更新的数据量变小,多次执行

    通业务数据的时候,可以执行每次执行多少行

    SET ROWCOUNT 1000来指定每次执行多少

     

     

    优化示例:

     

    问题:在测试环境查询6分钟,出不了结果

     

    SELECT  *

    FROM    TV_LogisticsPH

    WHERE   Col_015 >= DATEADD(MONTH, -1, GETDATE())

            AND ISNULL(Col_002, '') = ''

            AND ISNULL(Col_020, '') = ''

            AND Col_090 LIKE N'%'

            AND Col_049 LIKE N'%'

            AND Col_191 IS NULL

            AND EXISTS ( SELECT 1

                         FROM   TV_LogisticsXD AS T2

                         WHERE  Col_028 = T2.DD_102

                                AND DATEDIFF(Mi, ISNULL(DD_120, '2000-01-01'),

                                             GETDATE()) > 20

                                AND ISNULL(DD_120, '2000-01-01') > '2000-01-02' )

            AND NOT EXISTS ( SELECT Col_002

                             FROM   TA_LogisticsXDRemark AS T1

                             WHERE  DATEDIFF(Mi, T1.Col_005, GETDATE()) < 20

                                    AND Col_028 = T1.Col_002 )

            AND ISNULL(Col_020, N'') = N''

            AND NOT EXISTS ( SELECT TOP ( 1 )

                                    1

                             FROM   TA_LogisticsXDRemark T

                             WHERE  T.Col_002 = Col_028

                                    AND CHARINDEX(N'预计',

                                                  SUBSTRING(T.Col_003, 6, 3)) > 0

                             ORDER BY T.Col_005 DESC );

    问题分析:

    1)优化ISNULL(Col_020, N'') = N'' Col_020=''

    2TV_LogisticsXD 换为实体表

    3ISNULL(DD_120, '2000-01-01') > '2000-01-02' ) 改为 DD_120>'2000-01-02'

    4)去除ORDER BY T.Col_005 DESC

    此时查询语句能够在5S内出结果

     

    在表TA_LogisticsDDDetai的关联字段上[DD_102],建索引,1S内出结果

    建索引:                                                                                                    

    CREATE NONCLUSTERED INDEX [IX_TA_LogisticsDDDetail_New]

    ON [dbo].[TA_LogisticsDDDetail] ([DD_102],[DD_115])

    DORP  INDEX  IX_TA_LogisticsDDDetail_New ON [TA_LogisticsDDDetail]

     

    优化后语句:

    SELECT  *

    FROM    TV_LogisticsPH

    WHERE   Col_015 >= DATEADD(MONTH, -1, GETDATE())

            AND ISNULL(Col_002, '') = ''

            AND Col_020 = ''

            AND Col_090 LIKE N'%'

            AND Col_049 LIKE N'%'

            AND Col_191 IS NULL

            AND EXISTS ( SELECT 1

                         FROM   TV_LogisticsXD AS T2

                         WHERE  Col_028 = T2.DD_102

                                AND DATEDIFF(Mi, ISNULL(DD_120, '2000-01-01'),

                                             GETDATE()) > 20

                                AND DD_120 > '2000-01-02' )

            AND NOT EXISTS ( SELECT Col_002

                             FROM   TA_LogisticsXDRemark AS T1

                             WHERE  DATEDIFF(Mi, T1.Col_005, GETDATE()) < 20

                                    AND Col_028 = T1.Col_002 )

            AND NOT EXISTS ( SELECT TOP ( 1 )

                                    1

                             FROM   TA_LogisticsXDRemark T

                             WHERE  T.Col_002 = Col_028

                                    AND CHARINDEX(N'预计',

                                                  SUBSTRING(T.Col_003, 6, 3)) > 0 );


  • 相关阅读:
    Redis 详解 (一) StackExchange.Redis Client
    redis在.net架构中的应用(1)--利用servicestack连接redis
    .NET中使用Redis:http://www.cnblogs.com/yangecnu/p/Introduct-Redis-in-DotNET.html
    SQL Server日期函数总结
    SQL Server 日期和时间函数
    16Aspx源码论坛
    方差和偏差的区别
    写在中秋节的前?秒
    装系统那些事儿-1-电脑的启动流程
    查找重复的数
  • 原文地址:https://www.cnblogs.com/wugang/p/14232339.html
Copyright © 2011-2022 走看看