如何分析和优化我的SQL查询

时间:2009-08-14 10:43:40

标签: sql-server optimization

SELECT K.euclidNo,K.KlinikAdi,k.kisaAdi,
(SELECT COUNT(1) FROM Seanslar AS S
INNER JOIN Faturalar AS F ON F.fatura_id = S.refFatura_id
INNER JOIN BasilmisFaturalar AS BF ON BF.basilmisFatura_id = F.refBasilmisFatura_id
WHERE MONTH(S.tarihi)<MONTH(F.faturaTarihi) AND
S.refKlinik_id = K.klinik_id AND
S.durumuVT = 1 AND 
F.faturaTArihi BETWEEN '2009.06.01' AND '2009.06.30' AND
S.refFatura_id = F.fatura_id AND
F.iptalEdenKullanici_id is null
GROUP BY S.refKlinik_id) AS GecmisAydakiSeansSayisi,
(
SELECT kdvDahilToplamTutar  FROM BasilmisFaturalar AS BF
INNER JOIN Faturalar AS F ON F.refBasilmisFatura_id = BF.basilmisFatura_id
INNER JOIN Seanslar AS S ON S.refFatura_id = F.fatura_id
WHERE MONTH(S.tarihi)<MONTH(F.faturaTarihi) AND
S.refKlinik_id = K.klinik_id AND
S.durumuVT = 1 AND 
S.refFatura_id = F.fatura_id AND
F.faturaTArihi BETWEEN '2009.06.01' AND '2009.06.30' AND
BF.basilmisFatura_id = F.refBasilmisFatura_id AND 
F.iptalEdenKullanici_id is null
GROUP by kdvDahilToplamTutar
) as FaturaTutari,
(
    SELECT (COUNT(1)*KUA.fiyat) as t FROM Seanslar AS S
INNER JOIN Faturalar AS F ON F.fatura_id = S.refFatura_id
INNER JOIN BasilmisFaturalar AS BF ON BF.basilmisFatura_id = F.refBasilmisFatura_id
INNER JOIN KurumUrunAnlasmalari AS KUA ON KUA.urunAnlasma_id = S.refUrunAnlasma_id
WHERE MONTH(S.tarihi)<MONTH(F.faturaTarihi) AND
S.refKlinik_id = K.klinik_id AND
S.durumuVT = 1 AND 
F.faturaTArihi BETWEEN '2009.06.01' AND '2009.06.30' AND
S.refFatura_id = F.fatura_id AND
F.iptalEdenKullanici_id is null
GROUP BY S.refKlinik_id,KUA.fiyat
) AS SeansTutari
FROM Klinikler AS K
WHERE K.refKlinikGrup_id = 1

该查询回答了11秒。我该如何优化呢?它必须回答3或4秒钟。

感谢您的帮助。

5 个答案:

答案 0 :(得分:3)

替换子查询:

(
    SELECT (COUNT(1)*KUA.fiyat) as t FROM Seanslar AS S
INNER JOIN Faturalar AS F ON F.fatura_id = S.refFatura_id
INNER JOIN BasilmisFaturalar AS BF ON BF.basilmisFatura_id = F.refBasilmisFatura_id
INNER JOIN KurumUrunAnlasmalari AS KUA ON KUA.urunAnlasma_id = S.refUrunAnlasma_id
WHERE MONTH(S.tarihi)<MONTH(F.faturaTarihi) AND
S.refKlinik_id = K.klinik_id AND
S.durumuVT = 1 AND 
F.faturaTArihi BETWEEN '2009.06.01' AND '2009.06.30' AND
S.refFatura_id = F.fatura_id AND
F.iptalEdenKullanici_id is null
GROUP BY S.refKlinik_id,KUA.fiyat
)

派生表在klinik_id上加入KLINIKER,性能会大幅提升。

例如:

SELECT K.euclidNo,K.KlinikAdi,k.kisaAdi, IsNull(DeriveOne.ValCount, 0) AS GecmisAydakiSeansSayisi,
....
FROM Klinikler AS K
LEFT JOIN (SELECT S.RefKlinik_id, Count(*) AS ValCount, 
    FROM Seanslar AS S
    INNER JOIN Faturalar AS F ON F.fatura_id = S.refFatura_id
    INNER JOIN BasilmisFaturalar AS BF ON BF.basilmisFatura_id = F.refBasilmisFatura_id
    WHERE MONTH(S.tarihi) < MONTH(F.faturaTarihi) AND
    S.durumuVT = 1 AND 
    F.faturaTArihi BETWEEN '2009.06.01' AND '2009.06.30' AND
    S.refFatura_id = F.fatura_id AND
    F.iptalEdenKullanici_id is null
    GROUP BY S.refKlinik_id) AS DeriveOne ON DeriveOne.RefKlinik_id = klinik_id
WHERE K.refKlinikGrup_id = 1

答案 1 :(得分:2)

了解问题所在的最佳方法是在查询分析器中运行它,启用show Execution Plan选项。
(这取决于您使用的SQL Server版本,以及是否使用管理工具。)

运行后,查看图片中每个项目的费用属性,看看哪个最高。那是你的瓶颈。 您可以通过添加索引或修改SQL来修复它。

您可能希望查看的另一个属性是查询计划的每个操作中使用的行数,因为这会对性能产生很大影响。

答案 2 :(得分:0)

查询计划和执行计划有所帮助,但它可能因开发环境和生产环境而异。我建议你将查询拆分成各个部分并对其进行性能调整。您可以添加的一些最佳实践是

  1. 前缀表调用
  2. 添加(NOLOCK)提示
  3. 等可能会有所帮助 希望我能帮到你。

答案 3 :(得分:0)

这是一种在SQL Server上找到缺失索引的简单方法(我相信2005或更高版本)。列表顶部的索引将产生最高的收益。如果你错过了一个会产生重大影响的东西,它应该会向你跳跃。

SELECT 
    migs.avg_total_user_cost * 
        (migs.avg_user_impact / 100.0) * 
        (migs.user_seeks + migs.user_scans) AS improvement_measure, 
    'CREATE INDEX ' + UPPER(LEFT (PARSENAME(mid.statement, 1), 32)) + '_IXn'
        + ' ON ' + mid.statement 
        + ' (' + ISNULL (mid.equality_columns,'') 
        + CASE WHEN mid.equality_columns IS NOT NULL 
          AND mid.inequality_columns IS NOT NULL THEN ',' ELSE '' END 
        + ISNULL (mid.inequality_columns, '')
        + ')' 
        + ISNULL (' INCLUDE (' + mid.included_columns + ')', '') 
        AS create_index_statement, 
     migs.*, 
     mid.database_id, 
     mid.[object_id]
FROM 
    sys.dm_db_missing_index_groups mig
    INNER JOIN sys.dm_db_missing_index_group_stats migs 
        ON migs.group_handle = mig.index_group_handle
    INNER JOIN sys.dm_db_missing_index_details mid 
        ON mig.index_handle = mid.index_handle
WHERE migs.avg_total_user_cost * 
      (migs.avg_user_impact / 100.0) * 
      (migs.user_seeks + migs.user_scans) > 10
ORDER BY 
    migs.avg_total_user_cost * migs.avg_user_impact * 
    (migs.user_seeks + migs.user_scans) DESC

答案 4 :(得分:0)

管理工作室中的

运行此命令:

SET SHOWPLAN_ALL ON

然后运行您的查询。

它将为您提供一个非常详细的列表,列出SQL Server将您的查询转换为结果集的操作。查看输出并尝试了解它的含义。我通常会寻找“SCAN”,这是一个缓慢的部分,我尝试重写它,因此它使用索引。