减慢许多聚合查询到一个非常大的SQL Server表

时间:2011-04-14 18:23:13

标签: asp.net sql-server performance

我有一个自定义日志/事务表,可以跟踪我的用户在Web应用程序中的每个操作,它目前有数百万条记录,并且按分钟增长。在我的应用程序中,我需要实现一些预先计算用户在sql中的活动/操作的方法,以确定应用程序中的用户是否可以使用其他功能/操作。例如,在页面加载之前,我需要检查用户是否多次查看页面X.

(SELECT COUNT(*) FROM MyLog WHERE UserID = xxx and PageID = 123)

我正在使用连接进行几个类似的聚合查询来检查其他条件并且性能很差。每次页面请求都会进行这些检查,应用程序每分钟可以收到数百个请求。

我正在寻找通过sql和/或应用程序代码来提高应用程序性能的任何想法。

这是一个.NET 2.0应用程序并使用SQL Server 2008。

提前多多谢谢!

5 个答案:

答案 0 :(得分:3)

最简单的方法是将计数存储在表格中。然后,在添加记录(希望通过SP)时,您可以简单地增加聚合表中受影响的行。如果您真的担心计数失败,可以在详细信息表上设置触发器来更新聚合表,但是我不喜欢触发器,因为它们的可见性很低。

此外,这些计数需要如何更新?这可以是一天可以存储到表中的东西吗?

答案 1 :(得分:1)

查询这样的日志表可能比值得更麻烦。

作为替代方案,我建议使用memcache之类的东西来存储所需的值。只要您在每次命中时更新缓存,查询大型数据库表的速度就会快得多。 Memcache有一个内置增量运算符来处理这种事情。 这样,您只需要在第一次访问时查询数据库。

另一种方法是使用预先计算的表,根据需要进行更新。

答案 2 :(得分:0)

您是否已在UserID和PageID上编入MyLog索引?如果没有,那应该给你一些巨大的收益。

答案 3 :(得分:0)

托德这是一个艰难的过程,因为你正在执行的操作数量。 你检查过那个数据库的索引吗?

这是一个存储过程,您可以执行该过程以帮助至少找到有效的索引。我不记得我发现了什么,但它帮助了我:

CREATE PROCEDURE [dbo].[SQLMissingIndexes]
@DBNAME varchar(100)=NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    SELECT 
        migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) 
        * (migs.user_seeks + migs.user_scans) AS improvement_measure, 
        'CREATE INDEX [missing_index_' 
        + CONVERT (varchar, mig.index_group_handle) 
        + '_' + CONVERT (varchar, mid.index_handle) 
        + '_' + LEFT (PARSENAME(mid.statement, 1), 32) + ']'
        + ' 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
    AND 
        (@DBNAME = db_name(mid.database_id) OR @DBNAME IS NULL)
ORDER BY 
        migs.avg_total_user_cost 
        * migs.avg_user_impact 
        * (migs.user_seeks + migs.user_scans) DESC
END

我修改了一下以接受数据库名称。如果您不提供数据库名称,它将运行并为您提供有关所有数据库的信息,并为您提供有关哪些字段需要建立索引的建议。

要运行它,请使用:

exec DatabaseName.dbo.SQLMissingIndexes 'MyDatabaseName'

我通常会将可重用的SQL(Sproc)代码放在一个名为DBA的单独数据库中,然后从任何数据库中我可以说:

exec DBA.dbo.SQLMissingIndexes

举个例子。

修改

记得来源,巴特邓肯。 这是一个直接链接http://blogs.msdn.com/b/bartd/archive/2007/07/19/are-you-using-sql-s-missing-index-dmvs.aspx

但请记住,我确实修改了它以接受单个数据库名称。

答案 4 :(得分:0)

我们遇到了同样的问题,从几年前开始,从SQL Server迁移到OLAP多维数据集,当最近停止工作时,我们再次移动到Hadoop和其他一些组件。

OLTP(在线事务处理)数据库(SQL Server是其中之一)在OLAP(在线分析处理)方面不是很擅长。这就是OLAP多维数据集的用途。

当您编写和读取许多单独的行时,OLTP可提供良好的吞吐量。正如您刚刚发现的那样,当执行许多需要扫描多行的聚合查询时,它会失败。由于SQL Server将每个记录存储为磁盘上的连续块,因此扫描多行意味着需要多次磁盘提取。缓存会为您节省一段时间 - 只要您的表很小,但当您到达具有数百万行的表时,问题就会变得明显。

坦率地说,OLAP也不具备可扩展性,并且在某些时候(每天数千万条新记录),您将不得不转向更加分散的解决方案 - 付费(Vertica,Greenplum)或免费(HBase,Hypertable)。

如果两者都不是一个选项(例如没有时间或没有预算),那么现在你可以通过在硬件上花更多钱来减轻你的痛苦。您需要非常快的IO(快速磁盘,RAID),就像您可以获得的RAM一样。