Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Hello, World!
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  17:45[Войти] | [Зарегистрироваться]

Обсуждение материала
Несколько приемов работы с базами данных
Полный текст материала


Другие публикации автора: Сергей Дуплик

Цитата или краткий комментарий:

«... Данная статья предназначена в основном для тех, кто начинает работать с базами данных. Здесь собраны приемы, направленные на оптимизацию и ускорение работы с базами данных. ...»


Важно:
  • Страница предназначена для обсуждения материала, его содержания, полезности, соответствия действительности и так далее. Смысл не в разборке, а в приближении к истине :о) и пользе для всех.
  • Любые другие сообщения или вопросы, а так же личные эмоции в адрес авторов и полемика, не относящаяся к теме обсуждаемого материала, будут удаляться без предупреждения авторов, дабы не мешать жителям нормально общаться.
  • При голосовании учитывайте уровень, на который расчитан материал. "Интересность и полезность" имеет смысл оценивать относительно того, кому именно предназначался материал.
  • Размер одного сообщений не должен превышать 5К. Если Вам нужно сказать больше, сделайте это за два раза. Или, что в данной ситуации правильнее, напишите свою статью.
Всегда легче осудить сделанное, нежели сделать самому. Поэтому, пожалуйста, соблюдайте правила Королевства и уважайте друг друга.



Добавить свое мнение.

Результаты голосования
Оценка содержания

  Содержит полезные и(или) интересные сведения
[1]325%
 
  Ничего особенно нового и интересного
[2]650%
 
  Написано неверно (обязательно укажите почему)
[3]325%
 
Всего проголосовали: 12

Оценка стиля изложения

  Все понятно, материал читается легко
[1]880%
 
  Есть неясности в изложении
[2]220%
 
  Непонятно написано, трудно читается
[3]00%
 
Всего проголосовали: 10




Смотрите также материалы по темам:
[Вопросы скорости обработки]

Комментарии жителей
Отслеживать это обсуждение

Всего сообщений: 26

17-01-2009 06:38

Да, если выполняются запросы на добавление и модификацию записей. Потому есть мнение, что удаление индекса до массового добавления записей и обратное построение их после операции. Мною лично не проверялось, если кто имеет информацию - поделитесь.

Писал как-то импорт с массовыми вставками записей. Было много индексов по строковым полям (Код, Код поставщика, Код производителя, Код таможенный, Код нормированный, Наименование, ....). Импрорт выполнялся сутки. После того, как сделал предварительное удаление индексов (осталась парочка) с восстановлением после импорта, сам импорт сократился до 1.5 часов. Сами индексы строятся считанные секунды/минуты.


14-01-2009 17:02
Во-1, это еще один запрос к БД.
Спорить не буду: если есть проблема и ее решение имеет практическую ценность что стоит публикации, то решение верно.

Во-2, где гарантия, что за время работы триггера никто ничего не вставит? ...
Что что-то не вставят -- никакой, а что ничего при этом не изменится -- "уровень изоляции".

:param in(fieid,0)

Oracle такую конструкцию точно не поддерживает


13-11-2008 02:01
сообщение от автора материала
зачем восстанавливать идентификатор: если этот идентификатор используется как генератор суррогатного ключа, то значение этого ключа (и идентификатора) можно взять из только-что вставленной записи
Во-1, это еще один запрос к БД.
Во-2, где гарантия, что за время работы триггера никто ничего не вставит? Да, операция вставки и все, что есть в триггере, выполняется в одной транзакции. Но все же...
:param in(fieid,0)
Не могу сказать, поддерживает ли такую конструкцию Парадокс. SQL Server и Access поддерживают. Oracle - с ходу не помню.


10-11-2008 11:07
Спасибо за ответ. Использую DBE и Paradox 7.0.


10-11-2008 09:49
Лучше тогда
where (:ParamObsh = PObsh) Or (:ParamObsh = 0)
Возможно не каждый СУБД поддерживает такой синтаксис :ParamObsh in (PObsh,0)
 Cep


10-11-2008 08:45
У меня не работает структура вида:

:param in(fieid,0)

Формирую запрос:

select PObsh,POtdelenie
from KPodrazd
where :ParamObsh in (PObsh,0)

Выдает ошибку в 3-й строке: PObsh,0)

Запрос переделал иначе, но идея та же:

select PObsh,POtdelenie
from KPodrazd
where (:ParamObsh=PObsh) Or (:ParamObsh in (0))

Работает.

Почему не работает первый вариант?


03-10-2008 03:15
>>>А вообще статья правильная ... Предлагаю считать все
>>>замечания к статье ... ломанем пальцев и дутьем
>>>пузырей "оч.умелых специалистов"

+1


19-09-2008 07:36
Задумка правильная, но реализация требует изменений:

5. Устраняем повторяющиеся запросы
В этом разделе надо было указать, что использование конструкции select count(*) as cnt ... не просто увеличивает время Операции, а в принципе вредно, т.к. является источником труднонаходимых ошибок. Если Операция -- это insert в таблицу из которой делается выборка select count(*), то рано или поздно получим ошибку вставки (ведь БД многопользовательская и пока вторая транзакция собирается делать вставку на основе cnt = 0, первая транзакция уже сделала вставку и изменила cnt). Дальше описано все правильно.

9. Курсоры - это долго
Заголовок имеет отношение к Курсорам, а тело раздела имеет отношение к "Индивидуальной обработке" и "Массовой обработке".
Конструкции типа insert-select, а также delete(update)-select относятся к Массовой (bulk) обработке. Конечно, они работают в разы быстрее.
Надо было назвать раздел типа "Массовая обработка", а то и правда подумают, что Курсоры - это долго, а значит, плохо.

10. Восстанавливаем идентификатор в триггере
Спорный раздел. Непонятно, зачем восстанавливать идентификатор: если этот идентификатор используется как генератор суррогатного ключа, то значение этого ключа (и идентификатора) можно взять из только-что вставленной записи.
Мое мнение, этот раздел специфический для MS SQL Server. В других СУБД таких проблем нет, т.к. имеются стандартные механизмы возврата суррогатного ключа, например, массивы SQLCA (SQL Communication Area) или генераторы, значение из которых можно взять заранее и оно останется неизменным.
Или речь идет о чем-то еще.


17-09-2008 23:49
  А вообще статья правильная, есть конечно немного неточностей и не мешало бы уточнять к каким БД предлагаемое решение или более всего сооотвесвует или просто не применимо (как в случае с FB ":param in(fieid,0)"). Для новичков самое то. Предлагаю считать все замечания к статье (в том числе и мои) ломанем пальцев и дутьем пузырей "оч.умелых специалистов". :-)
 Seer


17-09-2008 23:42
> :param in(fieid,0) Нетривиально.

  Мало того IB и FB пошлют вас unknown и будут правы.
 Seer


17-09-2008 23:32
> наиболее эффективным способом повышения быстродействия часто является простой SQL оператор

  drop database

  :-)
 Seer


16-09-2008 03:02
:param in(fieid,0) Нетривиально.


15-09-2008 06:23
C апострофами малось запутался... Так примерно должно быть:

Query.SQL.Text := 'SELECT * FROM TABLE WHERE FIELD = ''' + Edit1.Text + ''''; // Не правильно
Query.SQL.Text := 'SELECT * FROM TABLE WHERE FIELD = :Parametr';              // Правильно
Query.ParamByName('Parametr').asString := Edit1.Text;

 Cep


15-09-2008 04:51
Хорошая статья. Я бы еще добавил пару слов о большом вреде НЕиспользования bind переменных в запросах.
Т.е. когда пишут

SELECT * FROM TABLE WHERE FIELD = ''' + Edit1.Text + '''';
вместо

SELECT * FROM TABLE WHERE FIELD = :Parametr';


15-09-2008 04:49
SELECT * FROM TABLE WHERE FIELD = :Parametr';
:Parametr' это что?
меня просто комментирование кавычек напрягает, в первом примере, а второй не понял :(


11-09-2008 01:56
сообщение от автора материала
Сергей Хачатуров
Придирайтесь. Буду исправлять, если соглашусь. :)


10-09-2008 02:38
На обобщенную информацию не тянет, очень многое справедливо только для определенных БД и компонентов доступа к данным.
Соответственно, придраться можно почти к каждому пункту. Иногда по-крупному.


08-09-2008 04:23
...

4. восстановили значение генератора:
     генератор = n + 1

5.                                                        сработал триггер

                                                          выполнился insert:
                                                            генератор = n + 2

                                                          (то есть - insert, конечно, не выполнился,
                                                           по причине условия уникальности, наложенного
                                                           на первичный ключ)

                                                           триггер завершился с ошибкой

И?..

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


08-09-2008 04:22
Пункт 10.

Не знаю, конечно, насчет MS SQL'а, но в Interbase/Firebird такое действие считается совершенным моветоном, и вот почему (в IB/FB генераторов можно насоздавать сколько угодно - но представим, что работа идет с одним и тем же генератором):

     наш триггер                                            другой триггер (для другой таблицы)

1.   сохранили значение генератора в n:
       n = генератор

2.   выполнили insert:
       генератор = n + 1

     (как я понимаю - в примере имеется в виду,
      что выполнен некий вспомогательный insert,
      в некую вспомогательную таблицу, для которой
      первичный ключ получается не из генератора,
      либо же просто не важен)

3.                                                        сработал триггер

                                                          выполнился insert:
                                                            генератор = n + 2

                                                          (в данном случае - выполнен _нужный_ insert,
                                                           для которого важно значение генератора,
                                                           из которого получился первичный ключ)

                                                          триггер завершился


08-09-2008 04:19
Пункт 4.

Есть такая замечательная возможность - определение собственных функция и процедур называется. И намного понятней для построения строки фильтра было бы написать простенькую процедуру вроде такой:


  procedure AddConditionToFilter(
    var Filter: String;
    const FieldName, Condition, Value: String;
    NeedToAdd: Boolean = True);
  begin
    if NeedToAdd then begin
      if Filter <> '' then
        Filter := Filter + ' and ';

      Filter := Filter + FieldName + ' ' + Condition + ' ' + Value;
   end;
  end;



и вынести ее в отдельный функциональный модуль. И тогда добавление условий к фильтру можно писать просто и понятно:


  sFilter := '';

  // первое поле
  AddConditionToFilter(sFilter, 'NumericField', '=', IntToStr(SpinEdit.Value), (SpinEdit.Value > 0));

  // второе поле
  AddConditionToFilter(sFilter, 'StringField', '=', Edit.Text, (Edit.Text <> ''));

  // третье поле
  AddConditionToFilter(sFilter, 'ClassField', '=', IntToStr(DBLookupComboBox.KeyValue),
    not VarIsNull(DBLookupComboBox.KeyValue) and (DBLookupComboBox.KeyValue <> 0));



06-09-2008 00:46
Поскольку объем текста превышает 5к, пишу продолжение. Кстати, ограничение странное :-)
>>> 11. Передаем соединение с базой данных в библиотеку
И опять нигде не сказана одна важная вещь, которую Delphi пишет в каждом проекте DLL. Только ее никто не читает. Ни те, кто знают (потому что знают), ни те, кто не знает (потому что не понимают, что это за фигня написана). Потому еще раз - требуется использование ShareMem при такой передаче. Хотя кто мешает передать только ConnectionString - непонятно. Да, создадутся разные подключения ну и что?
>>> Не нравится, как выполняется запрос
Хитро! А если человек получил запрос на форуме, он ему не нравится, но он даже не понимает, что он делает, только видит, что он выполняет то, что надо. А потом на другом форуме он получает другой совет, переделывает запрос по другому и в результате получается... ерунда. Так что еще один совет - не уверен - не обгоняй... тьфу, не знаешь, чего делает запрос - сперва разберись. Это сэкономит много времени потом, когда придется его модифицировать.
Разрешите пользователю вводить уточняющие запросы. Например, пусть пользователь ищет в базе абонентов Петрова из Москвы. База возвращает ему тысячу записей. Дайте возможность пользователю уточнить запрос без необходимости вновь вводить все данные - про Петрова и про Москву. Это как в Гугле - "Искать в найденном". Это очень удобно. Позвольте удалять уточняющие фильтры хотя бы как из стека. Поверьте, это ускоряет работу. Вопрос интерфейсной реализации этой "фичи" стоит рассматривать отдельно. Я сделал в виде меню: "Уточнить запрос", "Отменить уточнение", которая выключается, если уточняющих запросов нет, но это не совсем удобно. Уточняющие запросы удобно вводить уже в поле Filter.


06-09-2008 00:45
Ну, есть все-равно ряд замечаний.
>>> Исключением может быть ситуация, когда нужно выбрать из таблицы почти все поля
Вот я создал базу данных, где есть поля "Фамилия", "Имя", "Отчество", "Дата рождения", "Телефон". Мне нужно найти телефон по имени и фамилии сотрудника. Дата рождения мне не нужна. Следуя Вашей логике, я могу выбрать все поля (*), так как поле "Дата рождения" очень мало по сравнению с остальными запрашиваемыми полями. Шло время и я добавлял новые поля. Появились поля "Фотография", "Характеристика", еще какие-то большие поля. Но звездочка в запросе осталась, ибо кому знать, что при добавлении нового поля в базу потребуется переработать запрос поиска телефона сотрудника (!)
Вывод: ВСЕГДА используйте список полей, даже если у Вас есть подозрения, что база расти не будет. На самом деле, если Вы пишете проект не для своего эксклюзивного пользования, то база расти будет. А * - это временная мера, а нет ничего более постоянного, чем временное.
>>> 3. Строим фильтр
Попробуйте запустить Ваш код и убедитесь, что в конце оператора осталось лишнее and. Я предлагаю простое решение: в конце фильтра добавить условие (1=1). Оно всегда истинно, поддерживается всеми базами данных и мало. Далее, по этой же статье. Везде Вы используете параметры - и это, безусловно, правильно. В этом же разделе Вы параметры не используете. Это может быть опасно, если Вы передаете на сервер строковые данные, подготовленные пользователем. Умный пользователь может подготовить специальный SQL запрос в поле ввода, который скомпрометирует Ваши данные, или повредит их. Не допускайте этого даже в теории - используйте параметры. Вы знаете, что изменение строки SQL.Text приводит к перепостроению списка параметров. Потому запрос нужно строить в два прохода: сперва Вы строите строку фильтра, потом устанавливаете SQL.Text, потом (во второй проход!) выставляете параметры. Данный подход опасен - при изменении данных в полях ввода Вы рискуете создать неправильный запрос и получить неверный фильтр. Убедитесь в отсутствии несинхронизируемых обращений к полям ввода, а лучше - до составления запроса создайте локальные копии всех введеных на форме данных. Потом это может избавить Вас от головной боли.
Кстати, главу 8 (Исключаем условие из запроса) я бы поместил поблизости. Например, 4 номером. Потому что такое использование параметров в принципе оправдано при построении фильтра. Только не знаю, как это скажется на производительности - я формирую фильтр динамически, попробую делать и так.
Кстати, в ту же копилку: изменение SQL.Text приводит к парсингу запроса компонентами доступа к базе данных. Это недолго, но при наличии большого количества обновлений может несколько снизить производительность программы. Используйте временную переменную для создания запроса и потом однократного присвоения его SQL.Text. Помните: в большинстве случаев скорость и требуемая память - взаимоисключающие понятия. Размеры оперативной памяти растут быстрее, чем мощности процессоров, потому - ориентируйтесь на производительность, если нет явного требования обратного.
>>> 4. Накладываем фильтр
По этой главе могу заметить только одно - используйте SQL. Дело в том, что если у Вас данных очень много, а требуемых - очень мало, то фильтр выкачает все данные, а SQL.Text - только нужно. Пусть у Вас есть таблица со всеми абонентами Росии (краденая Центртелекомовская к примеру). Вы хотите найти телефон какого-то Петрова из Москвы. SQL.Text возвратит несколько сот записей, они быстро загрузятся, дальше поиск можно вести в нем. Но если Вы рассчитываете, что пользователь будет много и часто использовать поиск (фильтрацию) в относительно небольшом наборе данных - используйте Filter. Кстати, компоненты доступа к базам данных в большинстве своем разумны и не выкачивают ВСЕ данные с сервера сразу, а подкачивают их по мере необходимости.
>>> 6. Объединяем похожие запросы
Можно использоать динамическое создание и открытие запросов. Это тоже неплохо, если обращения в разным наборам данных независимы. Возможно, это вызовет снижение производительности - нужно смотреть.
>>> Построение новых индексов может положительно сказаться на одних запросах
Да, если выполняются запросы на добавление и модификацию записей. Потому есть мнение, что удаление индекса до массового добавления записей и обратное построение их после операции. Мною лично не проверялось, если кто имеет информацию - поделитесь.


05-09-2008 02:17
Неплохая статья по основам SQLя да ещё и с некими намёками на оптимизацию БД.
Только всё же в статье под названием "Несколько приемов работы с базами данных" ожидались приемы работы с БД, а не приемы построения SQL-запросов. Может быть, имеет смысл подумать над изменением названия, чтобы оно более соответствовало изложенному в статье материалу?


04-09-2008 14:07
Статья нормальная. Но, считаю, следовало бы отметить, что процентов 80 «тормозов» БД связаны в первую очередь с плохо сконструированной структурой  базы. Когда структура создается для решения сиеминутной задачи, без минимальных попыток разобраться в предметной области и хотя бы как-то спрогнозировать возможное развитие проекта. По мере развития проекта такая БД начинает обрастать массой непонятных таблиц, полей, триггеров и т.д., назначение которых не помнят даже старожилы...  Поэтому  наиболее эффективным способом повышения быстродействия часто является простой SQL оператор

Drop Table...

:)


02-09-2008 12:34
так лучше не делать:
inttostr(DBLookupComboBox.KeyValue);
KeyValue - типа Vaiant и может принимать значение null, что может привести к ошибке преобразовании типов.
Следует использовать IntToStrDef(DBLookupComboBox.KeyValue,0) или проверять с помощью VarIsNull.


02-09-2008 09:32
Хорошая статья. Я бы еще добавил пару слов о большом вреде НЕиспользования bind переменных в запросах.
Т.е. когда пишут

SELECT * FROM TABLE WHERE FIELD = ''' + Edit1.Text + '''';

вместо

SELECT * FROM TABLE WHERE FIELD = :Parametr';

 Cep


Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Какой месяц идет после марта?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.

Оценка содержания
 
Содержит полезные и(или) интересные сведения
 
Ничего особенно нового и интересного
 
Написано неверно (обязательно укажите почему)


Оценка стиля изложения
 
Все понятно, материал читается легко
 
Есть неясности в изложении
 
Непонятно написано, трудно читается

Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования