Начать просмотр результатов запроса до его завершения - PullRequest
2 голосов
/ 02 апреля 2010

Допустим, я запрашиваю таблицу с 500K строк. Я хотел бы начать просмотр любых строк в буфере выборки, который содержит результирующий набор, даже если запрос еще не завершен. Я хотел бы прокрутить через буфер выборки. Если я прокручиваю слишком далеко вперед, я хочу отобразить сообщение вроде: «Достигнута последняя строка в буфере извлечения .. Запрос не завершен».

  • Может ли это быть выполнено с помощью fgets () для чтения буфера выборки, пока запрос продолжает формировать набор результатов? Это подразумевает многопоточность *

Может ли такая функция, кроме директивы подсказки FIRST ROWS, предоставляться в Oracle, Informix, MySQL или других СУБД?

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

РЕДАКТИРОВАТЬ: То, что я предлагаю, может потребовать фундаментальных изменений в архитектуре сервера БД в отношении того, как они обрабатывают свои внутренние буферы выборки, например, блокировка набора результатов до завершения запроса и т. д. Функция, подобная той, которую я предлагаю, была бы очень полезна, особенно для запросов, выполнение которых занимает много времени. Зачем ждать, пока весь запрос не завершится, когда вы можете начать просматривать некоторые результаты, пока запрос продолжает собирать больше результатов!

Ответы [ 5 ]

5 голосов
/ 04 апреля 2010

Перефразируя:

У меня есть таблица с 500K строк. Специальный запрос без хорошего индекса для его поддержки требует полного сканирования таблицы. Я хотел бы сразу просмотреть первые возвращенные строки, пока продолжается полное сканирование таблицы. Затем я хочу просмотреть следующие результаты.

Кажется, что вам нужна какая-то система, в которой могут работать два (или более) потока. Один поток будет занят синхронным извлечением данных из базы данных и сообщением о ходе выполнения остальной части программы. Другой поток будет иметь дело с дисплеем.

А пока я хотел бы отобразить ход сканирования таблицы, например: "Поиск ... найдено 23 из 500 000 строк на данный момент".

Не ясно, что ваш запрос вернет 500 000 строк (на самом деле, будем надеяться, что это не так), хотя, возможно, ему придется просканировать все 500 000 строк (и вполне может найти только 23 строки, которые пока соответствуют). Определить количество строк, которые должны быть возвращены, сложно; определить количество строк для сканирования проще; определить количество уже отсканированных строк очень сложно.

Если я прокручиваю слишком далеко вперед, я хочу отобразить сообщение вроде: «Достигнута последняя строка в буфере предварительного просмотра ... запрос еще не завершен».

Итак, пользователь прокрутил 23-ю строку, но запрос еще не завершен.

Можно ли это сделать? Может быть как: spawn / exec, объявить курсор прокрутки, открыть, получить и т. Д .?

Здесь есть пара вопросов. СУБД (верно для большинства баз данных и, конечно, для IDS) остается привязанной к текущему соединению при обработке одного оператора. Получить обратную связь о том, как продвигался запрос, сложно. Можно посмотреть оценочные строки, возвращаемые при запуске запроса (информация в структуре SQLCA), но эти значения могут быть неверными. Вам нужно будет решить, что делать, когда вы достигнете строки 200 из 23, или вы попадете только в строку 23 из 5697. Это лучше, чем ничего, но это не надежно. Определить, как далеко продвинулся запрос, очень сложно. И некоторые запросы требуют фактической операции сортировки, а это означает, что очень трудно предсказать, сколько времени это займет, потому что данные не доступны, пока не будет выполнена сортировка (а после того, как сортировка завершена, для связи между СУБД и приложение для задержки доставки данных).

Informix 4GL имеет много достоинств, но поддержка потоков не является одним из них. Язык не был разработан с учетом безопасности нитей, и нет простого способа установить его в продукт.

Я думаю, что то, что вы ищете, будет легче всего поддерживать в двух потоках. В однопоточной программе, такой как программа I4GL, нет простого способа выключить и извлечь строки, ожидая, пока пользователь введет еще какой-нибудь ввод (например, «прокрутить следующую страницу, полную данных»).

Оптимизация FIRST ROWS является подсказкой для СУБД; это может или не может дать значительную выгоду воспринимаемой производительности. В целом, это обычно означает, что запрос обрабатывается менее оптимально с точки зрения СУБД, но быстрое получение результатов для пользователя может быть более важным, чем рабочая нагрузка на СУБД.


Где-то внизу, в ответе с большим количеством голосов, Фрэнк кричал (но, пожалуйста, не кричите):

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

OK. Трудность здесь заключается в организации IPC между двумя процессами на стороне клиента. Если оба подключены к СУБД, они имеют отдельные подключения, и поэтому временные таблицы и курсоры одного сеанса недоступны для другого.

Когда выполняется запрос, создается временная таблица для хранения результатов запроса для текущего списка. Устанавливает ли механизм IDS эксклюзивную блокировку для этой временной таблицы до завершения запроса?

Не все запросы приводят к временной таблице, хотя набор результатов для курсора прокрутки обычно имеет что-то примерно эквивалентное временной таблице. IDS не нужно устанавливать блокировку для временной таблицы, поддерживающей курсор прокрутки, потому что только IDS может получить доступ к таблице. Если бы это была обычная временная таблица, по-прежнему не было бы необходимости блокировать ее, потому что к ней нельзя получить доступ, кроме как через сеанс, который ее создал.

Что я имел в виду под строками 500k, так это nrows в запрашиваемой таблице, а не сколько ожидаемых результатов будет возвращено.

Возможно, более точное сообщение о состоянии было бы:

Searching 500,000 rows...found 23 matching rows so far

Я понимаю, что точное количество nrows можно получить в sysmaster: sysactptnhdr.nrows?

Возможно; Вы также можете получить быстрый и точный подсчет с помощью «SELECT COUNT (*) FROM TheTable»; это ничего не сканирует, а просто обращается к управляющим данным - вероятно, фактически к тем же данным, что и в столбце nrows таблицы SMI sysmaster: sysactptnhdr.

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

2 голосов
/ 01 августа 2012

Существует три основных ограничивающих фактора:

  1. План выполнения запроса. Если план выполнения имеет в конце блокирующую операцию (например, сортировку или активную буферизацию), механизм не сможет вернуть строки в начале выполнения запроса. Он должен дождаться полной обработки всех строк, после чего он как можно быстрее вернет данные клиенту. Время для этого само по себе может быть значительным, поэтому эта часть может быть применима к тому, о чем вы говорите. В целом, однако, вы не можете гарантировать, что запрос будет доступен в ближайшее время.

  2. Библиотека подключений к базе данных. При возврате наборов записей из базы данных драйвер может использовать пейджинг на стороне сервера или пейджинг на стороне клиента. То, что используется, может и влияет на то, какие строки будут возвращены и когда. Пейджинговая обработка на стороне клиента вынуждает сразу возвращать весь запрос, уменьшая возможность отображения любых данных, прежде чем они будут полностью обработаны. Тщательное использование правильного метода пейджинга имеет решающее значение для любой возможности отображения данных в начале срока существования запроса. *

  3. Клиентская программа использует синхронные или асинхронные методы. Если вы просто скопируете и вставите некоторый код веб-примера для выполнения запроса, у вас будет меньше шансов работать с ранними результатами, пока запрос еще выполняется - вместо этого метод будет блокироваться, и вы ничего не получите, пока все не будет Конечно, подкачка на стороне сервера (см. Пункт # 2) может облегчить это, однако в любом случае ваше приложение будет заблокировано, по крайней мере, на короткое время, если вы специально не используете асинхронный метод. Для тех, кто читает это и использует .Net, вы можете проверить Асинхронные операции в .Net Framework .

Если вы все сделаете правильно и будете использовать технику FAST FIRSTROW, вы сможете сделать то, что вы ищете. Но нет гарантии.

2 голосов
/ 02 апреля 2010

Это можно сделать с помощью аналитической функции, но Oracle должен полностью отсканировать таблицу, чтобы определить количество независимо от того, что вы делаете, если нет индекса. Аналитика может упростить ваш запрос:

SELECT x,y,z, count(*) over () the_count
  FROM your_table
 WHERE ...

Каждая возвращаемая строка будет иметь общее количество строк, возвращаемых запросом в the_count. Однако, как я уже сказал, Oracle должен будет завершить запрос, чтобы определить количество, прежде чем что-либо будет возвращено.

В зависимости от того, как вы обрабатываете запрос (например, блок PL / SQL в форме), вы можете использовать указанный выше запрос, чтобы открыть курсор, затем выполнить цикл по курсору и отобразить наборы записей и дать пользователю шанс отменить.

1 голос
/ 01 августа 2012

Итак, я размещаю свои комментарии в этом ответе. С точки зрения Oracle.

Oracle поддерживает свой собственный буферный кеш внутри глобальной области системы (SGA) для каждого экземпляра. Коэффициент попаданий в буферный кеш зависит от размера и в большинстве случаев достигает 90%, что означает, что 9 из 10 попаданий будут удовлетворены, не достигнув диска.

Учитывая вышеизложенное, даже если существует «путь» (так сказать) для доступа к буферной цепочке для выполняемого вами запроса, результаты будут сильно зависеть от коэффициента размера кэша. Если буферный кэш слишком мал, коэффициент попадания в кэш будет небольшим, и в результате увеличится количество операций ввода-вывода физического диска, что сделает буферный кэш ненадежным с точки зрения содержимого временных данных. Если буферный кеш слишком велик, то части буферного кеша будут использоваться не полностью, а ресурсы памяти будут потрачены впустую, что с точки зрения обработки приведет к слишком большой ненужной обработке при попытке получить доступ к буферному кешу, пока он не заглядывает в него. для данных, которые вы хотите.

Кроме того, в зависимости от размера кеша и памяти SGA, драйвер / оптимизатор ODBC может определить, когда и сколько использовать, что (буферизация кеша или прямой дисковый ввод-вывод).

С точки зрения попытки получить доступ к «буферному кешу», чтобы найти «строку», которую вы ищете, может быть (или в ближайшем будущем) сделать это, но не было бы способа узнать, что Вы ищете («Строка»), есть или нет, в конце концов.

Кроме того, полное сканирование таблицы больших таблиц обычно приводит к чтению с физического диска и более низкому коэффициенту попадания в буферный кэш. Вы можете получить представление об активности полного сканирования таблицы на уровне файла данных, запросив v$filestat и присоединившись к SYS.dba_data_files. Ниже приведен запрос, который вы можете использовать, и пример результатов:

 SELECT   A.file_name, B.phyrds, B.phyblkrd
 FROM     SYS.dba_data_files A, v$filestat B
 WHERE    B.file# = A.file_id
 ORDER BY A.file_id;

Поскольку все это испытание в значительной степени основано на нескольких параметрах и статистике, результаты того, что вы ищете, могут оставаться вероятностными из этих факторов.

1 голос
/ 04 апреля 2010

Я не уверен, как бы вы это сделали, так как запрос должен быть выполнен до того, как станут известны результаты. Ни одна РСУБД (о которой я знаю) не предлагает каких-либо средств для определения того, сколько результатов запроса было найдено до его завершения.

Фактически я не могу говорить о том, насколько дорогостоящей будет такая возможность в Oracle, потому что я никогда не видел исходный код. С другой стороны, я думаю, что это будет довольно дорого и может удвоить (если не больше) время, затрачиваемое на выполнение запроса. Это будет означать обновление атомарного счетчика после каждого результата, что недешево, если вы говорите о миллионах возможных строк.

...