如何改进用于存储大型版本数据集的选择查询?

时间:2010-03-27 13:45:33

标签: sql-server sql-server-2005

在工作中,我们构建了大型多页面Web应用程序,主要包括无线电和复选框。每个应用程序的主要目的是收集数据,但当用户返回他们之前访问过的页面时,我们会向他们报告他们之前的回复。在最坏情况下,我们可能有多达900个不同的变量和大约150万用户。

由于多种原因,使用仅插入方法来存储数据(而不是就地更新)是有意义的,这样我们就可以捕获有关与变量重复交互的历史数据。最终结果是每个变量每个用户可能有几个响应。

我们收集回复的表格看起来像这样:

CREATE TABLE [dbo].[results](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [userid] [int] NULL,
    [variable] [varchar](8) NULL,
    [value] [tinyint] NULL,
    [submitted] [smalldatetime] NULL)

其中id作为主键。

实际上每个请求都会产生一系列插入语句(每个变量提交一个),然后我们运行一个select来生成下一页的上一个响应(如下所示):

SELECT t.id, t.variable, t.value
    FROM results t WITH (NOLOCK)
    WHERE t.userid = '2111846' AND 
    (t.variable='internat' OR t.variable='veteran' OR t.variable='athlete') AND
    t.id IN (SELECT MAX(id) AS id
        FROM results WITH (NOLOCK)
        WHERE userid = '2111846' AND (t.variable='internat' OR t.variable='veteran' OR t.variable='athlete')
        GROUP BY variable)

在这种情况下,对于用户2111846,将返回变量“internat”,“veteran”和“athlete”的最新响应。

我们在索引表格时遵循了数据库调优工具的建议,而对于我们的数据,这是我们能够提出的最佳性能的选择查询版本。即便如此,由于该表接近100万条记录(而且我们可能有大约150倍的记录),似乎会有显着的性能下降。我们有一个相当优雅的解决方案,用于分割多个表格中的数据,这些表格一直运行良好,但我愿意接受有关如何构建更好版本的select查询的任何建议。我们经常使用这种结构来存储大量独立的数据点,我们喜欢它提供的好处。

所以问题是,如何提高选择查询的性能?我假设嵌套的select语句是一个坏主意,但我还没有找到一个同样可以执行的替代方法。

提前致谢。

注意:由于我们强调在这种情况下创建过度阅读,并且因为我们从未更新过,所以在这种情况下使用NOLOCK指令似乎没有任何惩罚(和一些优势)。

1 个答案:

答案 0 :(得分:3)

请勿使用NOLOCK提示。请改用snapshot isolation,只需在数据库上启用READ_COMMITED_SNAPSHOT ON。

另外,你说你想要“最近的”,但你选择了ID by ID,这是一个IDENTITY键。你不应该使用'最近'的日期时间吗?标识只会将插入顺序设为“最近”,这可能对域模型没有意义。

要返回您想要的数据,最好的方法是创建适当的群集密钥:

CREATE TABLE [dbo].[results](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [userid] [int] NULL,
    [variable] [varchar](8) NULL,
    [value] [tinyint] NULL,
    [submitted] [smalldatetime] NULL);

create clustered index cdxResults on results ([userid], variable, id DESC);

如果您有一个可能的变量类型表,那么可以通过在APPLY运算符中使用MAX来高度优化查询:

SELECT t.id, t.variable, t.value
FROM ( 
  SELECT 'internat' as variable
  UNION ALL SELECT 'veteran'
  UNION ALL SELECT 'athlete'
) as v
CROSS APPLY (
   SELECT TOP(1) id, variable, value
   FROM results 
   WHERE userid = @userid
   AND variable = v.variable
   ORDER BY id DESC
) as t

此查询将运行3搜索到聚簇索引,响应时间将始终为常量O(1),与数据大小无关。 IE浏览器。同一时间表中的100行,100万或10亿。