Получение большого количества записей из базы данных - PullRequest
0 голосов
/ 29 марта 2011

В моем приложении Windows иногда приходится выполнять запросы, которые возвращают 10000 записей. Я использую службы WCF для получения данных, и иногда это происходит очень медленно из-за огромного объема данных. Я использую базу данных SQL Server 2008.

Я хотел бы получить записи 100 на 100 для моего запроса sql, который возвращает 10000 записей. Есть ли способ справиться с такими случаями? Может ли курсор SQL справиться с этим?

В основном это похоже на подкачку данных или отображение данных в реальном времени в сетке. Но я хочу начать отображать записи до того, как все получится на клиентской машине. Когда объем данных огромен, я привык создавать BackgroundWorker для извлечения данных, но я не уверен, как объединить эти две функции. Было бы неплохо, если бы вы могли показать мне образец работы.

Ответы [ 4 ]

2 голосов
/ 29 марта 2011

Однажды у меня была похожая проблема, когда мне приходилось передавать миллионы строк по WCF. То, что сработало для меня, это чанкинг канал.

На стороне сервера ваш класс реализует что-то вроде этого:

void InitQuery(QueryString); // initializes datareader that pulls result out of DB
YourClass[] GetChunk(int ChunkSize); // puts the next x elements from the reader into array. If it returns null you're done.

С клиента вы устанавливаете запрос с первым, а затем читаете куски со второго. Вам не нужно беспокоиться о разбивке по страницам и т. Д. В запросе sql, просто получите следующие x записей из читателя, поместите их в ваш класс DataContract и верните его. SqlDataReader отслеживает, где вы находитесь. (Это может не очень хорошо масштабироваться для многих пользователей, хотя)

Убедитесь, что вы используете прокси на сервере между обращениями к серверу, поскольку он поддерживает состояние. Посмотрите в SessionMode.

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

Вы не упомянули, что вы используете, WinForms или WPF, но оба поддерживают способы отложенной загрузки данных в сетку. Вы хотите вызвать GetChunk из фонового потока, и, когда у него будут результаты, передать весь массив в поток пользовательского интерфейса, а затем зациклить его. (Не зацикливайте его из фонового потока, потому что вам нужно будет вызывать каждую строку в массиве. Это будет медленно)

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

2 голосов
/ 29 марта 2011

Вы можете использовать выражение Common Table, с функцией ранжирования Row_Number ... Вот пример из некоторого кода, который я написал:

CREATE PROCEDURE PagingSample
  @PageNumber int,
  @PageSize int
AS

WITH Results AS (
  SELECT 
    ROW_NUMBER() OVER(ORDER BY MR.MRN ASC) As RowNumber,
    MR.MRN
FROM 
  dbo.SomeTable MR WITH (NOLOCK)    
)

SELECT 
  R.RowNumber,
  R.MRN
FROM
  Results R
WHERE
  RowNumber > (@PageNumber * @PageSize) - @PageSize 
  AND RowNumber < (@PageNumber * @PageSize) + 1 

Теперь передайте номер страницы и размер вашегостраница в sproc, вот так:

Exec PagingSample @PageNumber = 3, @PageSize = 100

И вы получите записи с 201 по 300

1 голос
/ 29 марта 2011

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

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

Я думаю, что запрос должен быть разделен на диапазоны данных и извлекать одну маленькую порцию за раз, но если вы используете работу с точечной сеткой 4.0, тогда Параллельные циклы помогут в этом

я видел, что производительность хорошая по сравнению с обычными циклами

1 голос
/ 29 марта 2011

Я не думаю, что нужно использовать BackgroundWorker, поскольку данные должны быть загружены вместе со страницей.Если вы хотите, чтобы ваши данные отображались до остальной части страницы, единственный способ, который я мог бы себе представить, это отправить почти пустую HTML-страницу обратно клиенту с некоторым JS, который выполняется при загрузке страницы, а затем возвращается на сервер.чтобы получить данные сетки (через ajax) и остальную часть страницы.Это может быть громоздкой и запутанной задачей.

Подход, который вы можете использовать, - это загружать только те записи, которые вам нужны для первой страницы данных вашей сетки.Вы можете думать о результатах поиска Google, он не загружает все эти результаты поиска в память или вашу страницу в этом отношении, а только первую страницу данных.Когда вам нужны дополнительные результаты, он извлекает их.

Чтобы получить записи из вашей БД в пределах определенного диапазона записей, вы можете использовать такой запрос, который будет получать записи от 1 до 100.

SELECT UserID, FirstName
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY UserID, FirstName) AS ROW_NUM, UserID, FirstName
    FROM Users.Users
    ) as T1
WHERE T1.ROW_NUM BETWEEN 1 AND 100
ORDER BY T1.ROW_NUM

Этот SQL, очевидно, будет помещен в хранимую процедуру и вызван с параметрами.

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