Ускорение SQL в Linq ToList - PullRequest
       1

Ускорение SQL в Linq ToList

2 голосов
/ 25 сентября 2011

У меня есть таблица SQL с примерно 380 000 строк.

В SQL SMSS я выполняю этот запрос:

 SELECT Longitude, Latitude, street FROM [Stops].[dbo].[Members]   
 WHERE ABS(Latitude - 51.463419) < 0.005 AND ABS(Longitude - 0.099) < 0.005 

Он возвращает около 20 результатов почти мгновенно.

У меня есть веб-служба WCF для предоставления моих данных приложению Windows Phone:

public class Service1 : IService1
{
    double curLatitude = 51.463;
    double curLongitude = 0.099;

    public List<Member> GetMembers()
    {
        DataClassesDataContext db = new DataClassesDataContext();
        var members = from member in db.Members                            
where (Convert.ToDouble(member.Latitude) - curLatitude) < 0.005 && (Convert.ToDouble(member.Longitude) - curLongitude) < 0.005

select member;
        return members.ToList();
    }
}

Я полагаю, что он выполняет тот же запрос, но также добавляет элементы в список.

Проблемав том, что это занимает 7+ минут, тогда я получаю какое-то странное исключение, поэтому никогда не завершается.Тестер службы WCF в VS2010 просто заполняется памятью и использует много ЦП при выполнении этого.Мне кажется, что ToList делает что-то странное?

Ответы [ 2 ]

3 голосов
/ 25 сентября 2011

Вам не хватает abs-части в вашей версии LINQ.

Некоторые примечания.
Вы можете отслеживать SQL-запрос как минимум двумя возможными способами.

  1. Используйте профилировщик SQL и проверьте запрос там (затем вы можете вставить запрос в SQL Management Studio и сравнить вывод с вашим запросом выше).
  2. Вставьте db.Log = Console.Out; (или другой TextWriter) и проверьте окно вывода в Visual Studio.

Вы должны располагать свой DataClassesDataContext, лучший способ - поместить его в блок using:

public List<Member> GetMembers()
{
    using(DataClassesDataContext db = new DataClassesDataContext())
    {
        var members = from member in db.Members                            
        where (Convert.ToDouble(member.Latitude) - curLatitude) < 0.005
            && (Convert.ToDouble(member.Longitude) - curLongitude) < 0.005
        select member;
        return members.ToList();
    }
}
2 голосов
/ 25 сентября 2011

Здесь есть ряд проблем:

  • (редактировать: игнорировать эту точку; я неправильно прочитал 380 000 как данные, которые выбираются), это очень большой объем данных для запроса и выводапо сети;например, сколько времени это займет в Query Analyzer?Это займет как минимум столько времени где угодно
  • при загрузке этого в LINQ-to-SQL, у вас есть материальные издержки и накладные расходы менеджера идентификации;последнее можно решить, отключив отслеживание объектов в контексте данных;первое сложнее - если вы подозреваете, что это важно (может быть, иногда), может быть, что-то вроде «dapper» может загрузить это вместо этого (у него гораздо более эффективный материализатор, и он не включает менеджер идентичности)
  • WCF должен сериализовать эти данные, которые могут занимать довольно много ресурсов ЦП и памяти - затем он должен передаваться по сети (что требует пропускной способности).Если вы можете изменить формат, другие сериализаторы могут сэкономить здесь и CPU, и пропускную способность.

Итак;первое, что нужно сделать, это определить, куда идет время.

  • Я бы начал с его запуска из Query Analyzer;может быть, индекс отсутствует?
  • установите для ObjectTrackingEnabled значение false
  • , после этого отделите доступ к данным от WCF, чтобы увидеть, кто является виновником - время просто данные-шаг к списку
  • после этого, время DataContractSerializer сериализует эти данные и измеряет размер данных при сериализации (лично я бы тогда сравнил с protobuf-net - но это может быть не вариант,в зависимости от вашего сценария)
  • а затем измерьте время в сети

Здесь может потребоваться оптимизация любого или всех из них.

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