Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Переход по номеру записи, Быстро найти нужный номер записи в базе 
:(
    Опции темы
budg
  Дата 19.5.2006, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 21.12.2005

Репутация: нет
Всего: нет



ADO, MSSQL2000

Прошу подсказать вариант быстрого перехода по номеру записи в базе(таблице). Сейчас использую "MoveBy(n)", однако, при n=200000 (или даже 100000) переход занимает очень много времени - десятки минут. Причем заметил - от мощности  сервера зависит слабо.
Есть ли другие, не-MoveBy варианты?

Заранее спасибо.

 smile  
PM MAIL   Вверх
Vit
Дата 19.5.2006, 15:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Мдя, тяжёлый случай.... Общие рекомендации такие:

1. Забыть даже о возможности существования компонента TADOTable, а помнить что есть только TADOQuery
2. Забыть о существовании каких-то номеров записи, их нет и быть не может, таблица это не массив чтоб к записи обращаться по номеру. У вас должно быть поле в таблице которое каждую запись идентифицирует, например автоинкремент и по нему ключ. Если нет - добавить.
3. Использовать SQL запрос для получения данных из конкретной записи
4. Забыть о возможности чтения более десятка записей одним запросом, чтение миллиона записей... это нечто... Вы будете приятно удивлены что ваши "минуты" при переходе плавно превратятся в дни при запуске нескольких экземпляров программы на одной базе данных...
5. Прочитать вот эту статью: http://vingrad.ru/ART-DELPHI-002171 


--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
budg
Дата 19.5.2006, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 21.12.2005

Репутация: нет
Всего: нет



Согласен - случай тяжелый. 

ADOTable нет и в помине. Пользуюсь ADOQuery, собсно вот:

Код

procedure TForm1.FormCreate(Sender: TObject);
begin

 With ADOQuery1 do
    begin
    Close;
    SQL.Clear;
    SQL.Add('SELECT ID, OfferID FROM OfferEntry');
    Open;
    First;
//    MoveBy(11000);
    NumZ.Caption:=IntToStr(RecNo);
    NumRec:=RecNo;
    CurID:=StrToInt(ADOQuery1.FieldByName('ID').Value);
    CurOfID:=StrToInt(ADOQuery1.FieldByName('OfferID').Value);
    stop:=false;
    end;
//  Edit1.Text:='';

end;


и далее:

Код

procedure TForm1.Button1Click(Sender: TObject);
    var
        found: string;
        cur: string;
        cur1: integer;
        colR: integer;
    label bg;
    label st;
    begin
    NumRec:=0;
    cl:=1;
    com:=0;
    colR:=0;
    LDeleted.Caption:='УДАЛЕНО';
    ADOConnection1.Connected:=true;
    if Edit1.Text='' then ADOQuery1.MoveBy(0)
                     else
                     ADOQuery1.MoveBy(StrToInt(Edit1.Text));

......


Это всё не от хорошей жизни. Вынужден перебирать каждую строку записи в огромной таблице, ибо не знаю заранее её логического значения.
Может использовать поле с нумерованными строками? Но ведь перебор все равно не исчезнет. Да ладно с ним, с перебором, можно подождать. Мне надо выйти быстро на нужный номер записи, а вот это самое проблематичное... smile
Экземпляр проги только один - у меня. Ни у кого более его не будет.
За ссылку спасибо, почитаю.. smile

 
PM MAIL   Вверх
skyboy
Дата 19.5.2006, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: нет
Всего: 260



budg, пойми, когда у тебя в файле(чем и является база данных) размер блока(строка в отношениий структуры базы данных) нефиксирован, то при переходе от одной строки к другой надо постоячнно искать конец текущей блока, потом - конец следующего и т.д., т.к. бессмыслено работать как с массивом: <offset>=<counter>*<record_size> - ведь резмер записи не одинаков. А когда ты объявишь индекс, то доступ к строке с нужным тебе индексом(использование автоинкремента и даст тебе номер строки) буде облегчен - ядро будет "в курсе", что строка с индексом 5(5 строка!) находится в файле по смещению 200 байт, а строка с индексом 50 - по смещению в 1012354 байта. При этом не надо будет перебирать данные в поисках признака конца строки - смещения будут заданы явно. Конечно, если у тебя была удалена запись с индексом 42, а последняя строка имеет автоинкрементый индекс 2201, то никто не "заполнит" пустую позицию с номером-индексом 42, но ведь ты при проверке можешь удостовериться, что требуемая запись существует, правда ведь? ;) Так что с индексом намного проще и быстрее.. 
PM MAIL   Вверх
Vit
Дата 19.5.2006, 18:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Цитата(budg @  19.5.2006,  07:06 Найти цитируемый пост)
Вынужден перебирать каждую строку записи в огромной таблице, ибо не знаю заранее её логического значения.
Может использовать поле с нумерованными строками? Но ведь перебор все равно не исчезнет. Да ладно с ним, с перебором, можно подождать. Мне надо выйти быстро на нужный номер записи, а вот это самое проблематичное... 
Экземпляр проги только один - у меня. Ни у кого более его не будет


Так... ставим с головы на ноги... 

1. В чём логика проверки каждой строки? Опиши пожалуйста, возможно что это можно сделать одним запросом, если нет, то это надо писать на T-SQL курсорами, это даст выигрышь в производительности примерно 2-3 порядка в самом плохом случае, в хорошем - на 5-6 порядков.

2. Нумеровать строки надо обязательно!

3. Тот запрос что вы привели делать не в коем случае нельзя если таблица больше 1000 записей, убьете не только сервак но и сетку.

4. MoveTo использовать не желательно. Используйте запрос строки по её номеру который проиндексирован...


А вообще желательно описать здесь конкретно задачу, мы помозгуем вместе. Я уже года 2 как занимаюсь тем что переписываю такие вот ужастики в нормальный вид, и то что работало неделю почему-то начинает работать по 10 минут.... Скорее всего вы просто не с правильного конца решаете задачу, это очень частая проблема, особенно для тех кто только что перешел с локальных баз данных или вообще только начал работать с базами данных. Сервера могут работать по логике которую вы пытаетесь создать, но как правило это даёт примерно такой-же эффект как использование микроскопа для забивания гвоздей, гвозди забиваются но очень криво и замена окуляра помогает незначительно...
 


--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
budg
Дата 22.5.2006, 09:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 21.12.2005

Репутация: нет
Всего: нет



Задача, собственно, в следующем...
Есть в базе две таблицы (вполне большого размера). Назовем их условно А и В. Таблица В подчинена таблице А по ринципу "один ко многим", т.е. одной строке таблицы А соответствует множество строк таблицы В ( от одной до нескольких сотен). Программист который создавал базу,  построил связь таблиц через код проги клиента по некому полю ID . При удалении строки в табл. А, должны были удаляться строки в талице В. Все просто. Однако, он то ли забыл, то ли была еще какая задумка, но удаление строк в таблице В не реализовано. Удаляется только строка в табл. А. Строки в табл. В с данным значением индексного поля "подвисают". Хуже всего, что при создании новых записей, возможно пересечение значений индексных полей с "подвисшими" записями, что приводит к появлению ложной информации. Периодически это проявлялось. Впрочем, это можно рассматривать как "фичу", поскольку  удается восстановить случайно удаленные данные(пользователи все равно удаляют, несмотря на предупреждения).  Хотя это немного трудоемко. 
Для очистки таблицы от таких "подвисших" записей написал небольшую прогу.  Все получилось неплохо, кроме одного - сканирования таблицы и перехода к нужной записи. Проверять приходиться каждую строку  в табл. В на предмет наличия заголовка в табл. А. Отсюда все проблемы.  
Если подскажете, буду премного благодарен... smile   

Это сообщение отредактировал(а) budg - 22.5.2006, 09:26
PM MAIL   Вверх
TheCetus
Дата 22.5.2006, 10:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 134
Регистрация: 9.3.2006

Репутация: нет
Всего: 2



Судя по описанию все 'очистки' можно сделать одним SQL запросом...
опиши подробнее критерий удаления подвисших записей 
PM MAIL   Вверх
budg
Дата 22.5.2006, 11:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 21.12.2005

Репутация: нет
Всего: нет



Цитата(TheCetus @ 22.5.2006,  10:24)
Судя по описанию все 'очистки' можно сделать одним SQL запросом...
опиши подробнее критерий удаления подвисших записей


можно одним запросом - это точно...

А критерий очень простой - 

- текущая строка
если значения поля ID из табл. В нет в столбце ID табл. А - зачит удаляем (или заносим в список для удаления).
- след строка

Впрочем, пытаюсь создать некий программный инструмент не только для удаления, но и восстановления данных 
PM MAIL   Вверх
Vit
Дата 22.5.2006, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Ну обычный outer join даёт тебе список строк которые не прилинкованы. Что с ними делать? 

1) Или удалить:
Код

Delete from B
Where id not in (Select id From A)



2) Или перенести в новую таблицу и там с ними разбираться:

Код

Select * 
Into MyNewTable
From B
Left Outer Join A on A.id=B.id
Where A.id is null

Delete from B
Where id not in (Select id From A)



3) Или создать для них корреспондентные записи в мастер таблице:

Код

Insert into A (id, чего-то там по умолчанию)
Select B.id 
Into MyNewTable
From B
Left Outer Join A on A.id=B.id
Where A.id is null


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


--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
budg
Дата 22.5.2006, 16:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 21.12.2005

Репутация: нет
Всего: нет



Спасибо.
Буду разбираться. 
PM MAIL   Вверх
Vit
Дата 22.5.2006, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Vitaly Nevzorov
****


Профиль
Группа: Экс. модератор
Сообщений: 10964
Регистрация: 25.3.2002
Где: Chicago

Репутация: 14
Всего: 207



Ну спрашивай если чего... пока твоя задача из раздела когда никаких пошаговых проходов вроде не нужно, как и клиентских програм... Я таких случаев много поисправлял, Query Analyser практически единственное что нужно, да немного анализа что творится, а исправляется всё это несколькими запросами. Но даже если и нужен проход по записям, то и он организуется без всякой программы, прямо в Query Analyser при щпомощи курсоров, будет на 2-3 порядка медленнее чем запросом, но на много порядков быстрее чем с помощью клиентского приложения. 


--------------------
With the best wishes, Vit
I have done so much with so little for so long that I am now qualified to do anything with nothing
Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
PM MAIL WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Базы данных и репортинг"
Vit
Петрович

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами


Обязательно указание:

1. Базы данных (Paradox, Oracle и т.п.)

2. Способа доступа (ADO, BDE и т.д.)


  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • Вопросы по SQL и вопросы по базам данных не связанные с Дельфи задавать здесь

FAQ раздела лежит здесь!


Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Vit, Петрович.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Базы данных и репортинг | Следующая тема »


 




[ Время генерации скрипта: 0.1064 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.