Linq2Sql замедляется через короткое время - PullRequest
1 голос
/ 25 января 2012

В более крупном проекте мы решили использовать Linq2Sql в веб-сервисах (WCF). Мы «быстро» выяснили, что после добавления некоторых данных (с помощью небольшого консольного приложения, импортирующего данные о клиентах) веб-служба замедлилась - практически на весь срок службы этого приложения.

Каждый раз, когда мы перезапускали приложение, вначале казалось, что данные быстро импортируются, а затем замедляются после, возможно, 10-15 минут импорта.

Я решил попробовать создать пример приложения, имитирующего небольшие части нашего основного приложения.

  • Я должен добавить, что мы решили опустить Linq2Sql в веб-сервисах, заменив их на reqular sqlcommand / SqlConnection и т. Д.

Кто-нибудь знает, чем может быть вызвано замедление работы приложения?

Вот код для «свернутого» приложения, имитирующего некоторые запросы к базе данных:

Приложение, включающее операторы 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 ]

2 голосов
/ 25 января 2012

Вы используете один контекст данных.Контекст данных включает в себя:

  • менеджер удостоверений
  • средство отслеживания изменений

Это означает, что чем больше объектов вы касаетесь, тем толще они становятся.И чем толще он становится, тем больше работы приходится делать каждый раз.И чем медленнее он становится.

Не храните контекст данных дольше, чем вам нужно;например, единица работы должна быть очень маленькой и осторожной единицей.

ТОГДА НАЧНИТЕ НАЧАЛО

Поскольку L2S реализует IDisposable, вы также должны убедиться, что выраспоряжайтесь каждым контекстом данных, который вы используете.

0 голосов
/ 28 января 2012

Я узнал, как решить проблему.Некоторые данные уже были «предварительно загружены» (отложенная загрузка?), И это не было отключено.Таким образом, если вы хотите контролировать то, что должен делать LINQ, а НЕ делать «за кадром», вы должны отключить эту функцию.

DatabaseContext.DeferredLoadingEnabled = false;

Ошибка новичка, к сожалению, сказать: - |

0 голосов
/ 25 января 2012

Я видел некоторые значительные улучшения при вызове функций Linq2SQl, которые возвращают только 1 или несколько элементов с использованием предварительно скомпилированных операторов LINQ.

Для получения дополнительной информации, пожалуйста, ознакомьтесь с этим постом http://www.foliotek.com/devblog/unexpected-benefits-of-precompilation-of-linq/

0 голосов
/ 25 января 2012

Я наблюдаю похожее поведение в приложении, над которым работаю. В моем случае я причина очень большого потребления памяти сервером SQL.

Если вы работаете в аналогичной конфигурации (1 машина с клиентом, SQL-сервером, Visual Studio), посмотрите на использование памяти на вашем компьютере (проводник процессов, добавьте столбец виртуального размера и сортируйте его). если вы видите корреляцию между замедлением и виртуальным размером -> добавьте в свой компьютер больше ОЗУ или очистите ненужные процессы.

Кстати - если ответ о контексте данных имеет отношение к вашему делу, то сначала исправьте эту проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...