如何使用SQL Server CE表索引 - 这个查询值得做什么?

时间:2012-03-26 23:01:48

标签: sql indexing sql-server-ce

是一个学习过程,我终于设法获得了一个针对SQL Server Compact Edition运行的查询。

我最初的问题仍然存在,那就是如何提高性能。有几个人评论说我应该尝试索引我的查询,这就是我现在正在看的内容。

此查询将使一所学校的所有玩家都属于一个重量,并选择其中最高技能并将玩家初始值设置为等于真。

        cmd.CommandText = "UPDATE player " &
            "SET starter = 'TRUE' " &
            "WHERE NOT EXISTS" &
            "(SELECT school, weight, skill " &
            "FROM player b " &
            "WHERE b.school = player.school " &
            "AND b.weight = player.weight " &
            "AND b.skill > player.skill)"
        cmd.ExecuteNonQuery()

查询运行速度非常慢。

  • 我的玩家'桌上有~17万玩家
  • 每位玩家属于4500所学校之一
  • 每位玩家属于14个重量中的一个
  • 每所学校属于50个州之一

有什么方法可以将此查询编入索引以使其运行更快?或者我该怎么办,因为现在运行此查询需要花费大量时间。

如果它有助于解释我正在使用的内容,我将提供播放器表格的图像。 (不显示ID和firstName)

http://i44.tinypic.com/jkygcp.png

谢谢!

@rob - 这是我在程序中输入的查询。

        cmd.CommandText = "update p1 " &
                    "set starter = 'TRUE' " &
                    "from player as p1 " &
                    "left outer join player as p2 " &
                    "on p1.school = p2.school " &
                    "and p1.weight = p2.weight " &
                    "and p1.playerId <> p2.playerId " &
                    "and p1.skill <= p2.skill " &
                    "where(p2.playerId Is null)"
        cmd.ExecuteNonQuery()

4 个答案:

答案 0 :(得分:2)

我同意纳撒尼尔·福特的观点,第一步可能是稍微改写一下这个问题,但我可能会建议一个不同的方向(可能会或可能不会有效)。

我认为你的目标是将每个体重类别中每个学校的“最佳”球员标记为首发。我也认为你只想标记这个首发,如果有一个明确的最佳(技能严格大于学校/重量)。我可能没有最后的标准正确...因为它可能会留下一些学校/砝码没有标记的启动器(很容易修复与类似形式的第二个查询)。

使用窗口函数可以巧妙地表达这种“最佳组”查询,但我认为SQL Compact不支持这些。您可以将其表示为反加入。这很奇怪,但可以帮助建议索引。

update p1
set starter = 'TRUE'
from player as p1
left outer join player as p2
   on p1.school = p2.school
  and p1.weight = p2.weight
  and p1.playerId <> p2.playerId
  and p1.skill <= p2.skill
where p2.playerId is null

我们正在更新p1。让我们尝试加入p2所有与p1相同的学校/体重的玩家,与p1一样好或更好(让我们排除p1中的玩家我们谈论的是因为每个人都和自己一样好。如果我们找到一个同样好或更好的人,那么p1 就是首发。但是,如果我们找不到任何好或更好的人,这意味着left outer joinp2.playerId留下p1,那么我们就可以选择该学校/体重,并标记为create index player_i01 on player ( school, weight, skill, playerId ) 作为首发。 (该段有点松散;我希望它很清楚。)

反连接是表达不存在查询的一种方式。我认为优化器可以将一些或所有“不存在”的查询重写为反连接。这里的重点是建议一个索引(如果错过了这个技巧,可能会帮助优化器)。

如果该查询执行了您想要的操作,并且可以使用SQL Compact(我无权访问),并且实际上是正确的(再次 - 零测试),那么您可能会考虑这样的索引:< / p>

{{1}}

如果这些都没有为您提供所需的性能,那么请考虑构建一个工作表(可能是一个临时表)来划分工作。我会把它保存为另一个答案......; - )

答案 1 :(得分:1)

在这种情况下,您执行的用于运行sql的代码有点令人困惑。我在下面重申了这一点:

UPDATE player SET starter = 'TRUE' WHERE NOT EXISTS 
(
  SELECT school, weight, skill 
    FROM player b 
   WHERE b.school = player.school 
     AND b.weight = player.weight 
     AND b.skill > player.skill
)

让我们先来看一下内部的select语句。这个陈述实质上是要求一个结果表,其中包含来自表'玩家'的三列(学校,体重,技能)。您将此表别名为'b'。然后你继续过滤三件事; b.school是否相当于player.school等。

你的第一个问题是根据你的别名,b.school = player.school相当于player.school = player.school。对于前两个过滤器,将选择所有行 - 这是不必要的计算。但是,你的最终过滤器应该总是返回false,这就是为什么你的查询很可能花了这么长时间:所有行都将从你的内部select语句中返回。

假设在外部声明中,你将玩家别名为a,那么你将得到一个单独的结果,因为你现在正在询问玩家是否在同一所学校,具有相同的权重并且更好。 (1)在这种情况下,你正在做的是将每个玩家与其他玩家进行比较:170,000名玩家是170k ^ 2或大约390亿次比较......这就是为什么这个查询太慢了。

有两种方法可以解决您的问题。首先是以程序化的方式处理其中的一部分。

  1. 选择所有独特的学校作为查询
  2. 为每所学校运行类似的查询
  3. 另一个是做一个聪明的SQL连接。这里我使用'playerId'作为一个唯一标识符的列。 (希望你的桌子有一个。)(2)

    SELECT a.playerId 
      FROM player a INNER JOIN player b
        ON ( a.school = b.school AND a.weight = b.weight)
     WHERE a.skill > b.skill
    

    通过使用内置的连接功能(3),此查询应该运行得更快,并且可以生成所有匹配的表格(只有同一所在学校和相同权重的玩家),然后过滤靠技巧。原始结果表,预过滤器,将比您使用的小得多。

    最后一件事;使用“不存在”非常麻烦,可能会影响您的表现。尝试类似的事情;

    UPDATE player c SET starter = 'TRUE' WHERE c.player IN
    (
      SELECT a.playerId 
        FROM player a INNER JOIN player b
          ON ( a.school = b.school AND a.weight = b.weight)
       WHERE a.skill > b.skill
    )
    

    (1)注意:在某些sql实现中,内部语句中的'player'可能会被解释为外部语句中的'player',但我不确定这是否有保证。因此,您应该使用别名来确定。

    (2)我不是100%这会起作用,因为我没有你的桌子可以玩。

    (3)SQL Server通常用于快速制作这些东西。但你必须知道如何使用它。

答案 2 :(得分:1)

有关索引和性能主题的一般教程,我热烈建议您阅读:Use The Index, Luke!

在这种特殊情况下,您希望使DBMS能够有效地确定符合查询WHERE子句条件的行(非)存在。我对SQL Server Compact不太熟悉,但在大多数DBMS上,表{school, weight, skill}player上的复合索引应该可以解决问题。

答案 3 :(得分:0)

寻找与索引相关的改进的第一个地方是join和where子句。我希望状态,重量和学校(在玩家表中)的复杂聚类键会产生一些明显的改善。

我还建议在播放器表格中添加一个自动增量“行标识符”列。在此表上放置非群集主键索引。然后更新您的表以使用查询中的新主键字段:

WHERE b.RowId = player.RowId