如何使用索引优化选择查询

时间:2014-02-01 12:52:13

标签: sql sql-server indexing query-optimization

我不是专家。 我有以下查询,其中包含10个表 MainTable有10个字段1st Prime Key和9个表的其余外键,称为TableE1 - 10.

以下查询在每个表中进行外连接,我想用索引优化此查询。

我想知道,我们如何使用索引优化查询,此查询在36秒内获取10 lacs(100万)记录,我们可以减少多少时间?

MainTable包含10个lacs(100万)记录,TableE1-9每个表包含5000个记录

select M.RecID, 
M.E1, E1.Descr as E1_D, 
M.E2, E2.Descr as E2_D, 
M.E3, E3.Descr as E3_D, 
M.E4, E4.Descr as E4_D, 
M.E5, E5.Descr as E5_D, 
M.E6, E6.Descr as E6_D, 
M.E7, E7.Descr as E7_D, 
M.E8, E8.Descr as E8_D, 
M.E9, E9.Descr as E9_D
from ((((((((tableMain M  
    Left Outer Join TableE1 E1 ON (E1.RecID = M.E1) )
    Left Outer Join TableE2 E2 ON (E2.RecID = M.E2) )
    Left Outer Join TableE3 E3 ON (E3.RecID = M.E3) )
    Left Outer Join TableE4 E4 ON (E4.RecID = M.E4) )
    Left Outer Join TableE5 E5 ON (E5.RecID = M.E5) )
    Left Outer Join TableE6 E6 ON (E6.RecID = M.E6) )
    Left Outer Join TableE7 E7 ON (E7.RecID = M.E7) )
    Left Outer Join TableE8 E8 ON (E8.RecID = M.E8) )
    Left Outer Join TableE9 E9 ON (E9.RecID = M.E9)
Order by RecID

4 个答案:

答案 0 :(得分:2)

索引可能不会对此查询有太多帮助,因为查询没有过滤。您正在检索一百万条记录。在查询上花了多少时间来检索值以及处理查询花了多少钱?

SQL Server有一个很好的优化器,它将使用复杂的连接算法来进行连接。即使没有索引,查询也很有可能运行良好。

也就是说,同时包含RecIdDescr的每个“E”表的索引可以帮助查询:E1(RecId, Descr)E2(RecID, Descr),依此类推。这些是覆盖索引。对于此查询,SQL Server将使用这些索引而无需从数据页读取。仅索引RecId也无法正常工作,因为仍需要在数据页面上查找Descr数据。

请注意,如果RecId已经是主键并且Descr是表中唯一的列,那么这些索引将是不必要的(冗余?)。

编辑:

评论太长了(我认为)。

以下是优化此查询的一些想法:

首先,所有行都是必需的吗?例如,你可以添加一个top 1000来获得你需要的东西吗?花费大量时间将行传递回应用程序。考虑将它们放入临时表(select into)。这可能会跑得更快。

其次,order by需要多长时间?尝试在没有order by的情况下运行查询,看看它是否占据主导地位。

第三,descr字段有多长?如果它们很长,即使只有几千个可能会占据数据的大小。注意“非常长”这里意味着许多千字节,而不是几百字节。

第四,是descr字段varchar()char()(或nvarchar()nchar())。 char()nchar()是非常糟糕的选择,因为它们在结果集中占用了大量空间。

第五(可能应该是第一个),看一下执行计划。你提出了一个非常简单的场景,所以我假设执行计划是对第一个表的扫描,其中每个表都有索引查找。如果计划看起来不像这样,那么可能会有优化的机会。

编辑II:

我会再说一遍。将数百兆字节从服务器传输到应用程序需要时间,而30英寸秒则不合理。 (返回集有10个ID = 40个字节加上描述字段,每个记录可能是100个字节。)问题是数据库和应用程序之间的层设计,而不是数据库性能。

答案 1 :(得分:0)

如果您的表TableE1 - TableE9有大量记录,则需要在所有九个表中的RecID上创建索引。 我猜你现在有很多记录而且没有索引,因为对于这样一个简单的查询来说30秒真的很慢。

答案 2 :(得分:0)

让我们尝试以下步骤。

  • 在主表上创建一个包含所有列(E1到E9)的非聚集索引。
  • 在RecID列上的每个子表上创建非集群索引。

让我知道评论/结果。

答案 3 :(得分:0)

试试这个:

SELECT  pvt.*
FROM 
(
    SELECT z.RecID, /*z.ID1, z.ID2, z.ID3 ...,*/ z.FK_ID_Type, t.Descr
    FROM 
    (
        SELECT  x.RecID, /*x.ID1, x.ID2, x.ID3 ...,*/ y.*
        FROM    dbo.MainTable x 
        CROSS APPLY 
        (
            SELECT  x.E1, CONVERT(TINYINT, 1) -- E1
            UNION ALL 
            SELECT  x.E2, CONVERT(TINYINT, 2) -- E2
            UNION ALL 
            SELECT  x.E3, CONVERT(TINYINT, 3) -- E4
            UNION ALL 
            SELECT  x.E4, CONVERT(TINYINT, 4) -- E4
            UNION ALL 
            SELECT  x.E5, CONVERT(TINYINT, 5) -- E5
            UNION ALL 
            SELECT  x.E6, CONVERT(TINYINT, 6) -- E6
            UNION ALL 
            SELECT  x.E7, CONVERT(TINYINT, 7) -- E7
            UNION ALL 
            SELECT  x.E8, CONVERT(TINYINT, 8) -- E8
            UNION ALL 
            SELECT  x.E9, CONVERT(TINYINT, 9) -- E9
        ) y (FK_ID, [FK_ID_Type])
    ) z INNER HASH JOIN -- or INNER MERGE JOIN
    (
        SELECT t1.RecID, t1.Descr, CONVERT(TINYINT, 1) FROM dbo.TableE1 t1
        UNION ALL 
        SELECT t2.RecID, t2.Descr, CONVERT(TINYINT, 2) FROM dbo.TableE2 t2
        UNION ALL 
        SELECT t3.RecID, t3.Descr, CONVERT(TINYINT, 3) FROM dbo.TableE3 t3
        UNION ALL 
        SELECT t4.RecID, t4.Descr, CONVERT(TINYINT, 4) FROM dbo.TableE4 t4
        UNION ALL
        SELECT t5.RecID, t5.Descr, CONVERT(TINYINT, 5) FROM dbo.TableE5 t5
        UNION ALL
        SELECT t6.RecID, t6.Descr, CONVERT(TINYINT, 6) FROM dbo.TableE6 t6
        UNION ALL
        SELECT t7.RecID, t7.Descr, CONVERT(TINYINT, 7) FROM dbo.TableE7 t7
        UNION ALL
        SELECT t8.RecID, t8.Descr, CONVERT(TINYINT, 8) FROM dbo.TableE8 t8
        UNION ALL
        SELECT t9.RecID, t9.Descr, CONVERT(TINYINT, 9) FROM dbo.TableE9 t9
    ) t(ID, Descr, [Type]) ON z.FK_ID = t.ID AND z.FK_ID_Type = t.[Type]
) v
PIVOT( MAX(v.Descr) FOR v.FK_ID_Type IN ([1], [2], [3], [4], [5], [6], [7], [8], [9]) ) pvt;