一段时间后Linq2Sql放慢了速度

时间:2012-01-24 21:02:06

标签: c# linq sql-server-2008

在一个更大的项目中,我们决定在Web服务(WCF)中使用Linq2Sql。我们很快发现,在添加了一些数据后(通过导入客户数据的小型控制台应用程序),Web服务的速度变慢了 - 显然是该应用程序的生命周期。

每当我们重新启动应用程序时,它似乎在开始时快速导入数据,然后在导入10-15分钟后放慢速度。

我决定尝试创建一个模仿主要应用程序小部分的示例应用程序。

  • 我必须补充一下,我们决定在Web服务中省略Linq2Sql,用reqular sqlcommand / SqlConnection等替换它们。

有没有人知道应用程序的减速可能是由什么引起的?

以下是模仿某些数据库查询的“最小化”应用程序的代码:

App包括用于创建表的SQL语句:

using System;
using System.Collections.Generic;
using System.Linq;

using System.Text;

namespace Linq2SqlTest
{
    class Program
    {
        /*
         * USE [Linq2SqlTest]
            GO
            SET ANSI_NULLS ON
            GO
            SET QUOTED_IDENTIFIER ON
            GO
            CREATE TABLE [dbo].[Adresse](
                [id] [int] IDENTITY(1,1) NOT NULL,
                [person_id] [int] NOT NULL,
                [Gate] [nvarchar](50) NOT NULL,
                [Poststed] [nvarchar](50) NOT NULL,
                [By] [nvarchar](50) NOT NULL,
             CONSTRAINT [PK_Adresse] PRIMARY KEY CLUSTERED 
            (
                [id] ASC
            )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
            ) ON [PRIMARY]

            GO
            ALTER TABLE [dbo].[Adresse]  WITH CHECK ADD  CONSTRAINT [FK_Adresse_Person1] FOREIGN KEY([person_id])
            REFERENCES [dbo].[Person] ([id])
            GO
            ALTER TABLE [dbo].[Adresse] CHECK CONSTRAINT [FK_Adresse_Person1]
         * 
         * 
         * USE [Linq2SqlTest]
            GO
            SET ANSI_NULLS ON
            GO
            SET QUOTED_IDENTIFIER ON
            GO
            CREATE TABLE [dbo].[Items](
                [ItemID] [int] IDENTITY(1,1) NOT NULL,
                [ItemNumber] [nchar](10) NOT NULL,
                [PersonID] [int] NOT NULL,
                [name] [nvarchar](50) NULL,
             CONSTRAINT [PK_Items] PRIMARY KEY CLUSTERED 
            (
                [ItemID] ASC
            )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
            ) ON [PRIMARY]

            GO
            ALTER TABLE [dbo].[Items]  WITH CHECK ADD  CONSTRAINT [FK_Items_Person] FOREIGN KEY([PersonID])
            REFERENCES [dbo].[Person] ([id])
            GO
            ALTER TABLE [dbo].[Items] CHECK CONSTRAINT [FK_Items_Person]

         *
         * USE [Linq2SqlTest]
                GO
                SET ANSI_NULLS ON
                GO
                SET QUOTED_IDENTIFIER ON
                GO
                CREATE TABLE [dbo].[Person](
                    [id] [int] IDENTITY(1,1) NOT NULL,
                    [name] [nvarchar](50) NOT NULL,
                    [AddedDate] [datetime] NOT NULL,
                    [ssn] [nvarchar](50) NOT NULL,
                 CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED 
                (
                    [id] ASC
                )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
                ) ON [PRIMARY]

         */

        public static Random randomizer = new Random();

        public static String GenerateName()
        {
            int nLetterCount = (randomizer.Next() % 5) + 3;

            String s = "";
            for (int i = 0; i < nLetterCount;i++)
            {
                int r = (randomizer.Next() % 26)+97;
                s += Convert.ToChar(r);
            }
            return s;
        }
        public static String GenerateFullname()
        {
            String Fullname = "";
            int nNameCount = randomizer.Next() % 3;
            nNameCount++;
            while (nNameCount>0)
            {
                if (Fullname.Length == 0)
                    Fullname = GenerateName();
                else
                    Fullname += " " + GenerateName();
                nNameCount--;
            }
            return Fullname;
        }
        static void Main(string[] args)
        {
            DatabaseDataContext db = new DatabaseDataContext();

            for (int i = 0; i < 300000;i++ )
            {
                int personid = randomizer.Next() % 100;
                Person p = db.Persons.FirstOrDefault(_p=> _p.ssn == personid.ToString());
                if (p == null)
                {
                    p = new Person();
                    p.name = GenerateFullname();
                    p.ssn = personid.ToString();
                    p.AddedDate = DateTime.Now;
                    db.Persons.InsertOnSubmit(p);
                    db.SubmitChanges();
                    Adresse a = new Adresse();
                    a.person_id = p.id;
                    a.Gate = GenerateFullname();
                    a.Poststed = GenerateName();
                    a.By = GenerateName();
                    db.Adresses.InsertOnSubmit(a);
                    db.SubmitChanges();
                    int jj = randomizer.Next() % 10 + 1;
                    for (int j = 0; j < jj; j++)
                    {
                        Item item = new Item();
                        item.ItemNumber = randomizer.Next().ToString();
                        item.PersonID = p.id;
                        db.Items.InsertOnSubmit(item);
                        db.SubmitChanges();
                    }
                }
                else
                {
                    int jj = randomizer.Next() % 10 + 1;
                    for (int j = 0; j < jj; j++)
                    {
                        int number = randomizer.Next();
                        Item item = db.Items.FirstOrDefault(_i => _i.ItemNumber == number.ToString());
                        if (item == null)
                        {
                            item = new Item();
                            item.ItemNumber = number.ToString();
                            item.PersonID = p.id;
                            db.Items.InsertOnSubmit(item);
                        }
                        else
                        {
                            item.ItemNumber = randomizer.Next().ToString();
                        }
                        db.SubmitChanges();
                    }
                }
                Console.WriteLine("\r" + i + "   ");
            }
        }
    }
}

4 个答案:

答案 0 :(得分:2)

您正在使用单个数据上下文。数据上下文包括:

  • 身份管理员
  • 更改跟踪器

这意味着您触摸的对象越多,它就越胖。它越胖,每次都要做的工作就越多。它越慢越好。

不要让数据上下文超出您的需要;例如,工作单位应该是一个小而谨慎的单位。

然后开始AFRESH

由于L2S实现IDisposable,您还应该确保处置您使用的每个数据上下文。

答案 1 :(得分:0)

我在我正在处理的应用上看到类似的行为。在我的情况下,我的原因是SQL服务器的内存消耗非常大。

如果您运行的是类似的设置(1台带有客户端,SQL服务器,Visual Studio的计算机),请查看计算机上的内存使用情况(进程资源管理器,添加虚拟大小列并按其排序)。如果你看到减速和虚拟尺寸之间的相关性 - &gt;将您的计算机视为更多RAM,或清理不必要的进程。

BTW - 如果有关数据上下文的答案与您的案例相关,请先解决该问题。

答案 2 :(得分:0)

我在调用Linq2SQl函数时看到了一些重大改进,这些函数只使用预编译的LINQ语句返回1个或几个项目。

有关详细信息,请查看此帖http://www.foliotek.com/devblog/unexpected-benefits-of-precompilation-of-linq/

答案 3 :(得分:0)

我发现了如何解决问题。有些数据已经“预加载”(延迟加载?),并且没有禁用。因此,如果你想控制LINQ应该做什么,而不是“幕后”,你应该禁用这个功能。

DatabaseContext.DeferredLoadingEnabled = false;

新手的错误,伤心地说: - |