数据库优化之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 );


posted @ 2017-05-19 15:37  划破黑夜  阅读(77)  评论(0编辑  收藏  举报