五种提高 SQL 性能的方法

来源:互联网 发布:外贸开发信软件 编辑:程序博客网 时间:2024/05/21 06:19
    
Five Ways to Rev up Your SQL Performance 


本文节选自MSDN的文章《五种提高 SQL 性能的方法》,提出如何提高基于SQL Server应用程序的运行效率,非常值得推荐。对一些Traffic很高的应用系统而言,如何提高和改进SQL指令,是非常重要的,也是一个很好的突破点。
*文章主要包括如下一些内容(如感兴趣,请直接访问下面的URL阅读完整的中英文文档):

1, 从 INSERT 返回 IDENTITY  
SELECT @@IDENTITY

2, 内嵌视图与临时表  
临时表 - 在 tempdb 中的临时表会导致查询进行大量 I/O 操作和磁盘访问,临时表会消耗大量资源。
内嵌视图 -使用内嵌视图取代临时表。内嵌视图只是一个可以联接到 FROM 子句中的查询。如果只需要将数据联接到其他查询,则可以试试使用内嵌视图,以节省资源。

3, 避免 LEFT JOIN 和 NULL  
LEFT JOIN 消耗的资源非常之多,因为它们包含与 NULL(不存在)数据匹配的数据。在某些情况下,这是不可避免的,但是代价可能非常高。LEFT JOIN 比 INNER JOIN 消耗资源更多,所以如果您可以重新编写查询以使得该查询不使用任何 LEFT JOIN,则会得到非常可观的回报。

加快使用 LEFT JOIN 的查询速度的一项技术涉及创建一个 TABLE 数据类型,插入第一个表(LEFT JOIN 左侧的表)中的所有行,然后使用第二个表中的值更新 TABLE 数据类型。此技术是一个两步的过程,但与标准的 LEFT JOIN 相比,可以节省大量时间。一个很好的规则是尝试各种不同的技术并记录每种技术所需的时间,直到获得用于您的应用程序的执行性能最佳的查询。
DECLARE @tblMonths TABLE (sMonth VARCHAR(7))

4, 灵活使用笛卡尔乘积  
对于此技巧,我将进行非常详细的介绍,并提倡在某些情况下使用笛卡尔乘积。出于某些原因,笛卡尔乘积 (CROSS JOIN) 遭到了很多谴责,开发人员通常会被警告根本就不要使用它们。在许多情况下,它们消耗的资源太多,从而无法高效使用。但是像 SQL 中的任何工具一样,如果正确使用,它们也会很有价值。

其中一段示例代码,值得效仿:
-- 笛卡尔乘积则可以返回所有月份的所有客户。笛卡尔乘积基本上是将第一个表与第二个表相乘,生成一个行集合,其中包含第一个表中的行数与第二个表中的行数相乘的结果。因此,笛卡尔乘积会向表 @tblFinal 返回 12(所有月份)*81(所有客户)=972 行。最后的步骤是使用此日期范围内每个客户的月销售额总计更新 @tblFinal 表,以及选择最终的行集。

DECLARE @tblMonths TABLE (sMonth VARCHAR(7))
DECLARE @tblCustomers TABLE (    CustomerID CHAR(10),
            CompanyName VARCHAR(50),
            ContactName VARCHAR(50))
DECLARE @tblFinal TABLE (    sMonth VARCHAR(7), 
            CustomerID CHAR(10),
            CompanyName VARCHAR(50),
            ContactName VARCHAR(50),
            mSales MONEY)


DECLARE @dtStartDate DATETIME, 
    @dtEndDate DATETIME,
    @dtDate DATETIME,
    @i INTEGER

SET @dtEndDate = '5/5/1997'

SET @dtEndDate = DATEADD(DD, -1, CAST(CAST((MONTH(@dtEndDate) + 1) AS    
    VARCHAR(2)) + '/01/' + CAST(YEAR(@dtEndDate) AS VARCHAR(4)) + ' 23:59:59' AS DATETIME))
SET @dtStartDate = DATEADD(MM, -1 * 12, @dtEndDate)


-- Get all months into the first table
SET @i = 0
WHILE (@i < 12)
BEGIN
    SET @dtDate = DATEADD(mm, -1 * @i, @dtEndDate)
    INSERT INTO @tblMonths SELECT CAST(YEAR(@dtDate) AS VARCHAR(4)) + '-' +
                CASE 
                WHEN MONTH(@dtDate) < 10 
                    THEN '0' + CAST(MONTH(@dtDate) AS VARCHAR(2))
                ELSE CAST(MONTH(@dtDate) AS VARCHAR(2))
                END AS sMonth
    SET @i = @i + 1
END

-- Get all clients who had sales during that period into the "y" table
INSERT INTO @tblCustomers
    SELECT    DISTINCT
        c.CustomerID,
        c.CompanyName,
        c.ContactName
    FROM Customers c
        INNER JOIN Orders o ON c.CustomerID = o.CustomerID
    WHERE    o.OrderDate BETWEEN @dtStartDate AND @dtEndDate

INSERT INTO @tblFinal
SELECT    m.sMonth,
    c.CustomerID,
    c.CompanyName,
    c.ContactName,
    0
FROM @tblMonths m CROSS JOIN @tblCustomers c

UPDATE @tblFinal  SET 
    mSales = mydata.mSales
FROM @tblFinal f INNER JOIN 
    (
    SELECT    c.CustomerID,
        CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +
        CASE WHEN MONTH(o.OrderDate) < 10 
            THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))
            ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))
        END AS sMonth,
        SUM(od.Quantity * od.UnitPrice) AS mSales
    FROM Customers c
        INNER JOIN Orders o ON c.CustomerID = o.CustomerID
        INNER JOIN [Order Details] od ON o.OrderID = od.OrderID
    WHERE    o.OrderDate BETWEEN @dtStartDate AND @dtEndDate
    GROUP BY
        c.CustomerID,
        CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +
        CASE WHEN MONTH(o.OrderDate) < 10 
            THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))
            ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))
        END
    ) mydata on f.CustomerID = mydata.CustomerID AND f.sMonth = 
       mydata.sMonth 


SELECT    f.sMonth,
    f.CustomerID,
    f.CompanyName,
    f.ContactName,
    f.mSales
FROM @tblFinal f
ORDER BY
    f.CompanyName,
    f.sMonth


5, 拾遗补零  
这里介绍其他一些可帮助提高 SQL 查询效率的常用技术。假设您将按区域对所有销售人员进行分组并将他们的销售额进行小计,但是您只想要那些数据库中标记为处于活动状态的销售人员。您可以按区域对销售人员分组,并使用 HAVING 子句消除那些未处于活动状态的销售人员,也可以在 WHERE 子句中执行此操作。在 WHERE 子句中执行此操作会减少需要分组的行数,所以比在 HAVING 子句中执行此操作效率更高。HAVING 子句中基于行的条件的筛选会强制查询对那些在 WHERE 子句中会被去除的数据进行分组。

另一个提高效率的技巧是使用 DISTINCT 关键字查找数据行的单独报表,来代替使用 GROUP BY 子句。在这种情况下,使用 DISTINCT 关键字的 SQL 效率更高。请在需要计算聚合函数(SUM、COUNT、MAX 等)的情况下再使用 GROUP BY。另外,如果您的查询总是自己返回一个唯一的行,则不要使用 DISTINCT 关键字。在这种情况下,DISTINCT 关键字只会增加系统开销。
---------------------
中文URL:
http://www.microsoft.com/china/MSDN/library/data/sqlserver/FiveWaystoRevupYourSQLPerformanCE.mspx
英文URL:
http://msdn.microsoft.com/msdnmag/issues/02/07/DataPoints/

 





<script type="text/javascript"><!--google_ad_client = "pub-7390275636631344";google_ad_width = 728;google_ad_height = 90;google_ad_format = "728x90_as";google_ad_type = "text_image";google_ad_channel ="5095444487";google_color_border = "336699";google_color_bg = "FFFFFF";google_color_link = "0000FF";google_color_url = "008000";google_color_text = "000000";//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script> 
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老师进修被学校扣工资该怎么办 老婆性格太倔结婚一年想离婚怎么办 天正打图窗户线条太粗怎么办 孩子在幼儿园不敢跟老师说话怎么办 温州教育准考证号密码忘了怎么办 高等继续教育网打不开课程怎么办 安运继续教育的登录密码忘了怎么办 金蝶k3账套管理打不开了怎么办 仁和会计课堂app不能用怎么办 光大银行已经下卡了终审被拒怎么办 过了上诉期和申诉期该怎么办 北外大四学生要实习半年课程怎么办 电脑发给手机的文件过期了怎么办 农民给土地卖了30年后怎么办 家长发家长群作业太多老师怎么办 在考试中心补不了四级成绩怎么办 微信登录密码不记得了怎么办 欠农民工工资不给怎么办老板说没钱 国外期刊催问稿件不理睬怎么办 老公离不开老婆也离不开小三怎么办 出轨被老婆发现还和小三联系怎么办 老公出轨后回家老婆不想原谅怎么办 小三和原配打架都住院了怎么办 毕业太多年查不到学历认证怎么办 没有做税种核定开了票怎么办 在学信网上查不到学历信息怎么办 学信网手机号换了密码忘了怎么办 学信网手机号换了密码也忘了怎么办 学信网上学习形式是星号怎么办 新手机号已被注册微店买家怎么办 微信号被冻结了里面的钱怎么办 不懂公司产品却要接待老外怎么办 上菜时发现桌面摆不下新菜怎么办 超市买到过期产品商家不赔尝怎么办 皇帝成长计划2俘虏的士兵怎么办 晚上楼上有挪桌子的声音怎么办 金灶茶具出故障码e7怎么办 起亚k2灯泡掉进大灯总成怎么办 衣服上拆过线的针孔怎么办 驾考科目二坡道定点熄火怎么办 穿着超短裤感觉要漏屁股怎么办