Особенности и недостатки временных таблиц
Участников наших курсов часто интересует внутренняя логика работы временных таблиц.
Какие критерии индексирования временных таблиц? Где они хранятся? Нужно ли в явном виде их удалять?
Ответы на эти вопросы мы рассмотрим в данной статье.
Также мы приведем случаи, когда не нужно использовать временные таблицы.
Где хранятся временные таблицы?
Временные таблицы — это объекты СУБД, никаких временных таблиц на сервере 1С нет, и не путайте их с таблицами значений.
Под вопросом: «Где хранятся временные таблицы?» – имеется ввиду физическое расположение, т.е. либо жесткий диск, либо оперативная память.
Вероятно, этот вопрос чаще других остается без ответа, либо ответы на него кардинально различаются.
Но все сходятся в том, что временные таблицы создаются и хранятся в базе TempDB.
Действительно, все временные таблицы относятся к базе данных TempDB, но это вовсе не значит, что они обязательно будут записываться на диск.
Правильный ответ на этот вопрос звучит так: все временные таблицы по умолчанию создаются в оперативной памяти, а именно – в буферном кэше.
Конечно, есть исключения. Например, если таблица слишком большая, то сервер может принять решение сбросить ее на диск. Также возможна ситуация, когда сервер по каким-либо причинам решил отдать память под другие данные, тогда таблица тоже будет записана на диск.
Почему таблица создается именно в памяти? Тут все очевидно – дело в производительности, думаю, не стоит объяснять, что чтение из оперативной памяти гораздо быстрее чтения с диска, даже если этот диск SSD.
Проведем эксперимент и проверим, где создается временная таблица.
Пишем следующий запрос в консоли:
ВЫБРАТЬ 1 КАК Поле1 ПОМЕСТИТЬ ВТ
Запускаем трассировку SQL Profiler с событием SQL:BatchComplited, выполняем запрос в консоли и получаем следующий текст SQL запроса:
INSERT INTO #tt1 (_Q_001_F_000) SELECT 1.0
Здесь мы видим только заполнение временной таблицы, т.к. код создания временных таблиц в нашей трассировке не отображается.
Чтобы понять, где создается временная таблица, необходимо понять, откуда читаются данные – с диска или из памяти. Для этого используем показатель physical reads (количество физических чтений), т.е. сколько 8Кб страниц данных было прочитано с диска для выполнения запроса.
Чтобы получить значение этого показателя, необходимо выполнить создание и чтение временной таблицы в Management Studio.
Создаем новый запрос и пишем следующее:
create table #tt1 (_Q_001_F_000 int); -- создаем локальную временную таблицу tt1 INSERT INTO #tt1 (_Q_001_F_000) SELECT 1.0 – заполняем таблицу set statistics io on; -- включаем вывод статистики ввода/вывода select * from #tt1 -- читаем данные из таблицы set statistics io off; -- выключаем вывод статистики drop table #tt1 -- удаляем таблицу
После выполнения данного кода на закладке «Сообщения» получим следующий текст:
(строк обработано: 1) Таблица «#tt1_____________________________________________000000000066″. Число просмотров 1, логических чтений 1, физических чтений 0, упреждающих чтений 0, lob логических чтений 0, lob физических чтений 0, lob упреждающих чтений 0.
Самое важное здесь то, что данные с диска не читались, т.к. число физических чтений равно 0, при этом есть 1 логическое чтение, т.е. данные были прочитаны только из памяти.
Отсюда можно сделать вывод, что временные таблицы в большинстве случаев создаются и хранятся в оперативной памяти, исключения уже описаны выше.
Надо ли индексировать временные таблицы?
На дисках ИТС, на экзамене 1С: Эксперт, да и я на своих курсах говорю, что нужно индексировать поля условий и соединений во временных таблицах.
Эта рекомендация настолько очевидна, что уже практически никто не подвергает ее сомнению.
Но как показывает практика, чаще всего индексы во временных таблицах не используются, либо используются, но запрос выполняется еще медленнее, чем без них. Скажу даже больше: для себя я сделал вывод, что польза от индексов на временных таблицах – скорее исключение, чем правило.
Это не значит, что индексы не нужно использовать, это значит, что необходимо анализировать каждый конкретный случай, и случаев, когда индекс не нужен, значительно больше.
Именно поэтому на курсах по оптимизации постоянно делается акцент на то, что с каждой проблемой надо разбираться отдельно, а не слепо выполнять рекомендации, не понимая, почему эти рекомендации именно такие.
Давайте рассмотрим ситуацию с индексацией на примере.
Создадим временную таблицу с одним числовым полем и значениями от 1 до 1 млн.
Это можно сделать с помощью следующего пакетного запроса:
ВЫБРАТЬ 0 КАК Цифра ПОМЕСТИТЬ ВТ_Цифры ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 4 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 5 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 6 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 7 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 8 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 9 ; ////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ 100000 * Таб6.Цифра + 10000 * Таб5.Цифра + 1000 * Таб4.Цифра + 100 * Таб3.Цифра + 10 * Таб2.Цифра + Таб1.Цифра + 1 КАК Число ПОМЕСТИТЬ ВТ_Числа ИЗ ВТ_Цифры КАК Таб1, ВТ_Цифры КАК Таб2, ВТ_Цифры КАК Таб3, ВТ_Цифры КАК Таб4, ВТ_Цифры КАК Таб5, ВТ_Цифры КАК Таб6 ; ///////////////////////////////////////////////////////////// ВЫБРАТЬ ВТ_Числа.Число ИЗ ВТ_Числа КАК ВТ_Числа ГДЕ ВТ_Числа.Число = 777
Весь запрос выполняется в среднем за 1.2 секунды.
Если посмотреть трассировку SQL Profiler, то мы увидим следующее:
На создание таблицы уходит 1.1 секунда и еще 0.1 секунда на сканирование всей таблицы, чтобы вернуть нам 1 строку.
Давайте посмотрим, что изменится, если добавить индекс в таблицу ВТ_Числа.
На моем компьютере запрос стал выполняться в среднем за 6 секунд.
Время создания таблицы увеличилось с 1 секунды до 5.3, при этом даже поиск по индексу в таблице все равно происходит медленнее, чем сканирование: 0.5 сек. против 0.1 без индекса. Единственное, в чем этот запрос выигрывает, — немного меньше логических чтений: 2057 против 2233 при сканировании.
Используйте индексирование только в том случае, если вы видите от этого явный положительный эффект.
Надо ли явно удалять временные таблицы после создания?
Ответ будет зависеть от способа создания временной таблицы.
Если Вы используете временную таблицу только в одном пакетном запросе, то ваша таблица «живет», пока выполняется этот пакетный запрос. Это значит, что менеджер временных таблиц был создан неявно.
В данном случае MS SQL создает локальную временную таблицу с одной решеткой (#), например #tt1.
Как только пакетный запрос завершается, неявный МВТ закрывается, и автоматически последует команда «Truncate table», которая удаляет созданную таблицу.
Если временная таблица проиндексирована, то сначала будет удален индекс и только потом таблица.
Пример можно посмотреть выше в трассировке.
В данном случае нет необходимости использовать команду «УНИЧТОЖИТЬ», только если Вы не хотите создать в том же запросе новую таблицу с таким же именем, ну или считаете это хорошим стилем написания кода.
Здесь главное понимать, что таблица все равно будет удалена при завершении пакетного запроса.
Ситуация меняется, если Вы явно используете менеджер временных таблиц (МВТ), т.е. создаете соответствующий объект метаданных. В этом случае MS SQL создает глобальную временную таблицу с двумя решетками (##).
Такая таблица будет удалена в любом из следующих вариантов:
- в запросе использована команда УНИЧТОЖИТЬ
- вызван метод МенеджерВременныхТаблиц.Закрыть()
- объект МенеджерВременныхТаблиц перестал существовать, например, завершилась работа процедуры/функции, которая породила этот объект, или пользователь закрыл программу
Если Вы используете объект МВТ, то временные таблицы рекомендуется удалять одним из первых 2 методов, как только в них отпала необходимость, иначе они будут висеть в памяти сервера СУБД, пока процедура/функция не закончит работу, что не есть хорошо. Если же у Вас процедура, в которой был создан МВТ завершается как раз выполнением запроса, тогда, конечно, МВТ можно не удалять, т.к. сработает 3 условие.
Подведем итог: если Вы не используете МВТ, то явно удалять временную таблицу не требуется, она будет удалена после завершения пакетного запроса.
Если явное объявление МВТ используется, то рекомендуется удалить таблицу вручную, например, в запросе командой «Уничтожить», либо методом МВТ.Закрыть().
Минусы временных таблиц
Идеальных инструментов не бывает, тем более в мире 1С.
Давайте рассмотрим, какие проблемы может принести активное использование временных таблиц.
Чрезмерное разрастание базы TempDB
Если Вы активно используете временные таблицы, то у Вас может довольно сильно разрастаться база TempDB и в один прекрасный день может занять все свободное место на диске. Размер TempDB автоматически только увеличивается, но не уменьшается. Внутри файла место может как заниматься, так и освобождаться, но сам размер файла только увеличивается.
Типичная ситуация, установили обновление, и через несколько дней TempDB раздуло до неимоверных размеров, а потом выясняется, что разработчики переписали запросы с использованием временных таблиц, причем таблицы эти внушительного размера и их много.
Для исправления ситуации необходимо выполнить следующие команды:
dbcc shrinkfile (tempdev, ЖелаемыйРазмерФайлаДанныхМб) dbcc shrinkfile (templog, ЖелаемыйРазмерФайлаЛоговМб)
Чрезмерное упрощение запросов
Нельзя сказать, что это очень большой минус, но все же.
Часто временные таблицы используются как раз для упрощения сложных запросов, чтобы серверу было легче подобрать оптимальный план, и это правильно.
Но можно встретить и другую крайность: запрос, который вполне можно было бы написать без временных таблиц, и он бы работал быстро и оптимально, все равно пишут через временные таблицы. Просто разработчику лень думать, как это можно сделать по-другому.
Если можно написать оптимальный запрос без использования временных таблиц, то лучше обойтись без них.
Запрос с оптимальным кодом без временных таблиц в любом случае будет работать быстрее и использовать меньше ресурсов, чем запрос с временными таблицами.
Заключение
После прочтения статьи у Вас может сложиться мнение, что я не советую использовать временные таблицы, но это не так. Напротив, я активно их использую для оптимизации запросов, но делаю это только после того, как удостоверюсь в их эффективности в данном конкретном случае.
Временные таблицы — это инструмент для решения определенных задач, а не волшебная таблетка на все случаи жизни.
Ускорение и оптимизация систем на 1С:Предприятие 8.3. Подготовка на 1С:Эксперт по технологическим вопросам
Бурмистров Андрей
PDF-версия статьи для участников группы ВКонтакте
Мы ведем группу ВКонтакте – http://vk.com/kursypo1c.
Если Вы еще не вступили в группу – сделайте это сейчас и в блоке ниже (на этой странице) появятся ссылка на скачивание материалов.
Статья в PDF-формате
Вы можете скачать эту статью в формате PDF по следующей ссылке: Ссылка доступна для зарегистрированных пользователей)
Ссылка доступна для зарегистрированных пользователей)
Ссылка доступна для зарегистрированных пользователей)
Ссылка доступна для зарегистрированных пользователей)
1с по умолчанию создает индексы для справочника по типу:
Ссылка, Ссылка + код, Ссылка + наименование.
Если я выбираю в запросе данные справочника (например одно поле наименование или ссылка и наименование) и делаю условие отбора в секции “ГДЕ” по наименованию, нужно ли помещать данные в ВТ и потом индексировать по полю наименование ? Или это избыточно, по-сколько индексы уже есть от платформы и их будет достаточно без создания ВТ и дальнейшего индексирования.
Евгений, здравствуйте.
Для справочника создаются индексы, поля в которых расположены немного в другом порядке: Наименование + Ссылка и Код + Ссылка.
Наименование стоит на первом месте, поэтому индекс по этому полю при отборе по справочнику будет использоваться и выборка будет очень быстрой.
Если вы поместите результат этого запроса во временную таблицу, индекс по наименованию там автоматически не появится т.к. это уже другая таблица.
Здравствуйте!
Есть ли разница в производительности, если после уничтожения (не индексированной) временной таблицы создать новую временную таблицу с тем же именем (запрос без менеджера временных таблиц)? Будет ли СУБД переиспользовать уничтоженную (очищенную) временную таблицу? Как это возможно проверить через профайлер?
Будет ли выигрыш в производительности, если заменить 20 временных таблиц (не индексированных, с небольшим количеством строк от 50 до 500, без менеджера временных таблиц) на один запрос без временных таблиц, только вложенные запросы? Сейчас текст запроса легче воспринимать через временные таблицы, а также временные таблицы можно будет (в будущих задачах) переиспользовать в других соединениях, не переписывая текст запроса.
Здравствуйте.
В одной из версий фирма 1С анонсировала оптимизацию работы с врем. таблицами, оптимизация как раз и заключалась в том, что при уничтожении временной таблицы она просто очищается, и может быть переиспользована в будущем, если кому-то потребуется таблица с такой же структурой.
Следовательно создание второй врем. таблицы на доли секунды будет быстрее чем первоначальное создание.
Как это проверить, если кратко то смотрите через EE или профайлер имя созданной таблицы, потом по методу описанному здесь смотрите ее состав
> Будет ли выигрыш в производительности, если заменить 20 временных таблиц (не индексированных, с небольшим количеством строк от 50 до 500, без менеджера временных таблиц) на один запрос без временных таблиц, только вложенные запросы?
Понятия не имею, я не знаю что за запрос, какой у него план, какой состав таблиц, какая СУБД и вообще может они и так быстро выполняется.
Проще всего переписать запрос и посмотреть будет станет ли быстрее и стабильнее, какой смысл гадать.
Андрей, спасибо вам большое за ответ!
Добрый день. А можно переменную менеджера временных таблиц назначить глобальной, что бы использовать в разных процедурах модуля? Передача переменной в процедуру через параметр не подходит, поскольку после формирования временной таблицы программа ждет некоторых действий от пользователя.
Дмитрий, здравствуйте.
Честно говоря думаю что нет, но лучше всего взять да попробовать, верно? :)
Подскажите, пожалуйста, если во время выполнения больших запросов с огромным количеством временных таблиц tempDb вырастает до верхних пределов, но после завершения всех запросов она хоть и большая, но практически пустая – это является проблемой? Могут ли эти пустоты использоваться эффективно далее при работе? или необходимо сжимать базу?
Добрый день!
После уничтожения объекта типа Запрос в коде 1С – платформа закрывает курсор и СУБД самостоятельно зачищает TempDB, если считает нужным. Но так-же если запрос создает несколько временных таблиц содержащих значительное количество строк, причём для финальной выборки они уже не нужны – можно их явным образом удалить, даже конструктор запроса знает про это. А вот принудительной очистки TempDB не требует (кроме возможно каких-то аварийных ситуаций).
Добрый день. Подскажите, пожалуйста, как будет правильно:
Нужно сделать запросом выборку, которая будет использоваться несколько раз. Например, она будет служить левой таблицей для других таблиц. Я могу 1) Сформировать ВТ с этой выгрузкой и через МенеджерВТ подгружать ее в запросы. Нужно будет каждый раз создавать описание ВТ, и в какой-то момент я могу попутать тип данных в колонке (кстати, нужно ли всегда указывать этот тип)? 2) выгрузить эту выгрузку в таблицу, которую объявлю в разделе переменных и использовать по мере надобности, буду подгружать ее в запросы как параметр? Спасибо
Добрый день!
Не совсем понятно что Вы имеете в виду. Достаточно создать запрос с МенеджеромВременныхТаблиц, например так:
МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
И пока этот менеджер будет существовать – все созданные в запросе временные таблицы будут доступны.
Описание… Никаким описанием обычно не пользуюсь, мне достаточно иногда комментариев и всё. Придерживайтесь одних и те-же правил именования – вам самому будет в дальнейшем легче. Если ошибаетесь часто – тщательнее проверяйте код.
По поводу переменных: если это будет переменная модуля – как только управление вернётся в клиентский контекст – переменная будет уничтожена (при следующем обращении к серверу создана заново но ее значение будет Неопределено), использовать реквизит объекта или реквизит формы в качестве экземпляра Менеджера временных таблиц вам не позволит платформа. Поэтому предпочтительнее за 1 вызов получить все требуемые данные с сервера сразу. Выше описано поведение актуальной платформы без режима совместимости в режиме управляемого приложения.
Если на какой-то вопрос не ответил – пожалуйста уточните.
Здравствуйте.
Подскажите, в чем может быть причина. При работе с отладчиком в какой-то момент появилась ошибка:
Временная таблица уже существует “ИмяВТ”. При этом запрос не изменялся.
Опишите ситуацию поподробнее, пока не очень понятно как это воспроизводится. Что именно вы делаете?
Здравствуйте.
А могли бы вы привести пример, когда индексирование действительно нужно?
Скажем так индексирование временных таблиц это точно не “серебряная пуля” и использовать его имеет смысл только если одновременно:
1.временная таблица большая или очень большая.
2.время выполнения запроса неудовлетворительно велико и есть необходимость его сократить.
Это необходимые условия, но не достаточные (достаточных пока никому не удалось сформулировать) т.е. в любом случае следует делать замеры на выполнение запроса/запросов с использованием индекса и без него.
Если эта временная таблица используется несколько раз (в одном запросе или в нескольких (через МенеджерВременныхТаблиц)) по одинаковому условию соединения шансы на выигрыш по скорости серьёзно возрастают.
Здравствуйте!
У Вас на картинке с подписью “Посмотрим, что изменится, если добавить индекс в таблицу ВТ_Числа” иллюстрация к git-flow
Доброго дня, Евгений!
Спасибо, исправили.
при анализе ТЖ заметил что строка МенеджерВременныхТаблиц.Закрыть() выполняется 692738, т.е. 692 секунды???
сами запросы еще не раскопал, но в любом случае странно что удаление таблиц через Truncate может занимать столько времени
или при закрытии еще на что-то может уходить время?
и дополнительно хотел уточнить
в ТЖ как я понимаю идет учет в десятитысячных долях секунды
для данного примера это выглядит так 11:44.2406-6927375
аналогичным образом я настраивал и лог ТЖ
gt property=”duration” value=”100000″
а вот тут “http://www.gilev.ru/privacystatement/” у вас написано что duration учитывается в секундах
“query:ge property=»Duration» value=»10000″ — ограничивает минимальную длительность 10 секундами”
1. В ТЖ для 8.2 время указывается в десятитысячных долях секунды, а в ТЖ для 8.3 в миллионных долях секунды. Если у вас 8.3, то удаление идет 6,9 сек.
2. Удаление ВТ может работать долго если ВТ очень большая (миллионы записей) или если диски сильно загружены (надо смотреть логи PerfMon).
3. Видимо ошибка в статье, 10000 это будет 1 секунда, а не 10.
ну там явно не миллионы записей, ну может пара сотен тысяч
диски флэшовые, очень хорошие
мне вот кажется что в замер попадает не только усечение временных таблиц, а вообще выполнение всех запросов объекта “Запрос” :))
потому что время примерно совпадает с длительностью всего этапа получения данных с сервера (по данным внутренней статистики, скажем так, ключевых операций)
в общем готовлю базу для замеров
в итоге замер показал проблемы совсем в другом месте
Хорошо что получилось разобраться самостоятельно.
Надо просто сравнить замеры 1С с замерами в профайлере, тогда все станет понятно.
удивила странность в ТЖ
Андрей, добрый день! Спасибо большое за статью, очень полезно и информативно. У меня вопрос, произвели переход на 8.3.,теперь при попытке открыть проводки документа (Дт/Кт) регистра бухгалтерии возникает ошибка “Попытка вставки неуникального значения в уникальный индекс: Microsoft SQL Server Native Client 10/0: Не удается вставить повторяющуюся строку ключа в объект «dbo.#tt35» с уникальным индексом «idx35»”. Я так понимаю что проблема со временной таблицей. Но вот вопрос, что делать дальше. Как можно исправить ситуацию? Можете дать рекомендацию.
Сходу, без анализа ситуации могу предложить попробовать следующие варианты:
– Поставить режим совместимости с 8.2
– Сделать ТиИ
– Сделать выгрузку в DT файл и загрузку из него
Если это не поможет тогда уже надо будет шаманить на месте
Добрый день, Андрей! Очень полезная информация. Глобальный вопрос в том, что лучше для манипуляций с данными использовать Менеджер временных таблиц и через язык запросов проводить модификацию таблицы или лучше все же выгружать в ТЗ и старым добрым способом работать операторами найти и менять значения в Таблице, удалять и добавлять строки и колонки=)?
В качестве конкретного вопроса. Что более быстрее и оптимальнее будет отрабатываться:
1. Оператор “Найти” по таблице значений
2. Отбор по виртуальной таблице через оператор “Где” Набор данных порядка 1 млн. строк
Правильный ответ: провести опыт и посмотреть на вашем сервере и ваших данных.
подскажите пожалуйста как в 83 можно кэшировать мвт между серверными вызовами? в 82 можно было его положить в хранилище значений, а отныне больше нет…
Попробуйте использовать временное хранилище
ПоместитьВоВременноеХранилище(< Данные>, < Адрес>)
ПолучитьИзВременногоХранилища(< Адрес>)
Добрый день! Подскажите, если я помещаю во временную таблицу данные, которые изначально индексированы, то эти поля во временной уже не индексированы?
Допустим, запрос:
выбрать Т.Ссылка, Т.Контрагент, Т.Подразделение
Поместить ВТ
ИЗ Документ.ПоступлениеТоваровУслуг КАК Т;
Ссылка ведь всегда индексирована, и если дальше в запросе мы по этой ссылке будем соединять эту таблицу с другой по ссылке, то имеет смысл заново индексировать поле Ссылка (при большом количестве записей)? (про чтение данных из документов, а не из регистров сейчас речи не идет).
> если я помещаю во временную таблицу данные, которые изначально индексированы, то эти поля во временной уже не индексированы?
Да, во временной таблице индекса по этим полям уже не будет.
> имеет смысл заново индексировать поле Ссылка (при большом количестве записей)?
Это зависит от вашего запроса и ваших данных. Попробуйте сделайте индекс на временной таблице и замерьте время выполнения. Зачастую индекс на временных таблицах не используется, либо используется но на его создание тратится больше времени чем на сканирование всей таблицы. Проведите опыт и посмотрите поможет ли индекс на временной таблице именно в вашем случае.
Андрей, спасибо за ваш труд. Курс по оптимизации мне очень понравился, хорошо структурирован, все по делу и без воды. За статьи и обратную связь отдельное спасибо!
Спасибо, за добрые слова, по таким комментарием понимаешь что все делалось не зря.
Следующая версия курса должна быть еще лучше :)
Кажется у вас опечатка или ошибка… ))
>Как только пакетный запрос завершается, неявный МВТ закрывается, и >автоматически последует команда «Truncate table», которая удаляет >созданную таблицу.
Скорее всего имелось в виду Drop table.
Truncate table – Удаляет все строки в таблице, не записывая в журнал удаление отдельных строк.
А я думал заметит ли кто – нибудь :)
Да, 1С всегда используется Truncate вместо Drop, что бы по возможности не создавать новую таблицу со такой же структурой, а использовать уже существующую, но принципиально сути это не меняет.
не в тему – прочитал и опять нахлынуло, имхо, как хотелось бы, чтобы действительно толковые головы разработчиков платформы 1С приложили усилия к продвижению по пути (в целом очень сложному пути) к избавлению от этих временных таблиц при написании запросов вместо создания сомнительной полезности управляемых форм и тем более Такси
Уже пора рубрику открывать “Осторожно! Гилев!” или “Киноляпы Гилева” (это про видеоуроки).
Похоже к нам заглянули старожилы Мисты ))
Ok, но здесь не получится развести традиционный флуд ;)
Вообще без конкретики с Вашей стороны сложно на это что-то ответить.
И непонятно, как этот комментарий вообще относится к временным таблицам.
Не понял. Вы серьезно говорите, что если используется явно МВТ, то создаются глобальные таблицы. Но глобальные таблицы существуют до тех пор пока не завершаться все сеансы (ВСЕ, а не только тот spid, который ее создал). То есть выход из процедура или функции (неявное закрытие МВТ), я уже молчу о сбоях, не приведут к уничтожению глобальной таблицы.
2) Если таблица глобальная, то она будет доступна всем сеансам, то есть если 2 пользователя выполняют одинаковую процедуру, то они будут мешать друг другу, то есть они не смогут параллельно их создавать, то есть возникнет проблема изоляции.
ЗЫ: Вообще не понимаю зачем обсуждать индексы временной таблицы, они ничем не отличаются от индексов обычных таблиц, кроме как что средствами 1С нельзя создать более одного индекса.
1) глобальные таблицы существуют до тех пор пока не завершаться все сеансы (ВСЕ, а не только тот spid, который ее создал)
—
Вы не правы, в контексте 1С глобальная таблица уничтожается в любом из трех перечисленных в статье случаев. Можете самостоятельно проверить в Profiler. При штатном завершении программы, никаких сбоев при работы временных таблиц не будет.
2) Если таблица глобальная, то она будет доступна всем сеансам, то есть если 2 пользователя выполняют одинаковую процедуру, то они будут мешать друг другу, то есть они не смогут параллельно их создавать, то есть возникнет проблема изоляции.
—
Вы снова ошибаетесь.
СУБД присваивает уникальные служебные имена временным таблицам, выглядят они примерно так «##tt1_____________________________________________000000000087».
Таким образом 1С сеанс никак не сможет прочитать данные временной таблицы другого сеанса. Более того, если бы то о чем вы говорите было бы возможно, то 1С вообще бы не смогла нормально работать в многопользовательском режиме.
3) Вообще не понимаю зачем обсуждать индексы временной таблицы, они ничем не отличаются от индексов обычных таблиц, кроме как что средствами 1С нельзя создать более одного индекса.
—
Да, я заметил что вы не понимаете.
Смысл статьи в том, что индексы на временной таблице нужно создавать не всегда и везде, а только там, где от этого есть реальная польза, т.е. где затраты на создание индекса перекрывается выигрышем в скорости чтения. Сейчас же многие разработчики слепо следуют рекомендации, не отслеживая при этом используется ли вообще созданный ими индекс, а если да, то приносит ли он желаемый эффект.
“Сейчас же многие разработчики слепо следуют рекомендации, не отслеживая при этом используется ли вообще созданный ими индекс, а если да, то приносит ли он желаемый эффект.”
Сорри за некропостинг, но я прямо себя вспомнил некоторое время назад, когда сдал спеца по платформе и гордо везде совал индексы. И очень увидился, увидев, что запрос БЕЗ индексов (в моем случае) стал работал в два раза быстрее :)
Да, к сожалению такое бывает чаще чем хотелось бы.
Провел эксперимент с индексированием временной таблицы на SQL Server 2012. Как и ожидалось, с индексом выборка работает существенно быстрее, чем без: примерно 1 миллисекунда против 80. По статистике чтений все также в пользу индекса. Не совсем понятно, почему у вас получился такой результат.
Вот поэтому я и говорю что нужно смотреть в каждом конкретном случае.
Поставил SQL Server 2014, платформа 8.3, результат такой же как в статье, запрос без индекса все равно работает быстрее чем с индексом.
ещё бы, именно MS SQL 2014 представлялся публике, как отличный инструмент “инмемори”-оптимизации. На других серверах и версиях верно “нужно смотреть в каждом конкретном случае”.
Дело здесь не в In-Memory OLTP, временная таблица и так была в памяти. Просто именно на моем компьютере данный запрос работает быстрее со сканированием, на другом компьютере с другой версией СУБД возможна другая ситуация.
Быстрее работает выборка (ВЫБРАТЬ ВТ_Числа.Число ИЗ ВТ_Числа КАК ВТ_Числа ГДЕ ВТ_Числа.Число = 777) или вставка + выборка?
На 2014 и 8.3 быстрее именно вставка в таблицу без индекса, сама выборка без индекса медленнее, но в итоге затраты на создание индекса так велики, что для данного запроса получается выгоднее его не создавать.
это ок, меня смутило что у вас select с индексом медленнее отработал.
В момент написания статьи использовалась платформа 8.2 и SQL Server 2008 R2, там селект действительно работал медленнее.
Хорошая статья, но по пункту “Надо ли индексировать временные таблицы?” – типовая рекомендация правильная, и лучше указывать вместо “Используйте индексирование только в том случае, если вы видите от этого явный положительный эффект.” формулировку “Используйте нужно индексировать поля условий и соединений во временных таблицах во всех случаях, кроме тех где нет явного положительного эффекта.”
Кроме того Вы привели частный пример, где создается одна таблица и производится выборка по одному полю, но если бы Вы привели пример запроса, где данные из первой таблицы выбираются не единожды, то результат был бы совершенно другой (вспомните хотя бы многоэтажные запросы ЗУПа).
Также не указан пример при соединении двух таблиц значительного объема.
Для себя я сделал вывод, что:
– индексирование по полям поиска не следует делать, если поиск по таблице выполняется 1-3 раза, тогда table scan без создания индекса сработает быстрее
– индексирование по условиям соединения не следует делать, если соединяемая таблица содержит НЕ БОЛЕЕ трех записей, тогда nested loop также отработает быстрее.
>по пункту «Надо ли индексировать временные таблицы?» — типовая рекомендация правильная, и лучше указывать вместо «Используйте индексирование только в том случае, если вы видите от этого явный положительный эффект.» формулировку «нужно индексировать поля условий и соединений во временных таблицах во всех случаях, кроме тех где нет явного положительного эффекта.»
Типовая рекомендация говорит, что поля условий и соединений нужно индексировать ВСЕГДА и никаких если.
>«нужно индексировать поля условий и соединений во временных таблицах во всех случаях, кроме тех где нет явного положительного эффекта.»
Вы предлагаете делать лишнюю операцию и лишний раз занимать ресурсы сервера. Допустим что разницы во времени не заметно т.к. железо сглаживает углы, и индекс на таблице не используется, так зачем же делать лишнюю операцию? Тем более что со временем нагрузка может увеличится и тогда разница в выполнении может быть заметна.
>Кроме того Вы привели частный пример, где создается одна таблица и производится выборка по одному полю, но если бы Вы привели пример запроса, где данные из первой таблицы выбираются не единожды, то результат был бы совершенно другой (вспомните хотя бы многоэтажные запросы ЗУПа).
Также не указан пример при соединении двух таблиц значительного объема.
Именно поэтому я и говорю что не нужно отказываться от индексов на временных таблицах, их нужно использовать, но только если есть явный эффект.
>индексирование по полям поиска не следует делать, если поиск по таблице выполняется 1-3 раза, тогда table scan без создания индекса сработает быстрее
Всегда зависит от конкретной ситуации
>индексирование по условиям соединения не следует делать, если соединяемая таблица содержит НЕ БОЛЕЕ трех записей, тогда nested loop также отработает быстрее.
Если в таблице 3 строки, нет абсолютно никакого смысла ее индексировать, ни поля соединений ни условий. Nested Loops с поиском по индексу никак не связан, при возможности Nested Loops может использовать индекс для поиска.
Еще раз подтверждает, что экзамены от 1с- это муть.
Не соглашусь с вами, просто на официальных курсах иногда дают слишком универсальные рекомендации, как бы перестраховываясь.
Андрей, вы представляете вчерашнего студента, который сдал на Эксперта и понял, что он “Великий Процессор”, с этого времени?
И всем своим подчиненным он дает задание, делать так, как на Великом Экзамене от 1С..
И не важно, что всё работать начинает всё хуже, и хуже.
Важно, что по правилам от 1С..Платформа которой содержит ошибки, не исправленные годами..
Кстати, в комментариях есть подобный пример.
Еще одно кстати ), если вы автор курса, мне нравится как он преподносится. Был курс по мобильной платформе, там было очень много “воды”. Здесь всё хорошо сжато.
Неплохо)
Руслан, Вы описывают гипертрофированного специалиста, ярого фаната 1С, который готов в кулачном бое доказать SAP’еру, что 1С круче :))
Конечно, такие “спецы” бывают, но их не очень много.
Здесь нужно правильно относится к экзаменам 1С.
С одной стороны, подготовка к ним позволяет в ограниченный срок получить определенный набор знаний.
С другой стороны, нужно понимать, что это все-таки учебные задачи.
И они часто далеки от практики.
Поэтому, свежеиспеченного 1С:Специалиста нельзя сразу бросать в одиночку на важные проекты.
Полученные знания еще должны быть обработаны напильником реальных внедрений.
P.S.
Да, Андрей автор курса
Этот курс разрабатывался около года, поэтому считаем, что он получился высокого качества.
Огромное спасибо!!! я очень редко применяю временные таблицы, хотя работала в Российской компании (я из Казахстана), так вот руководитель программистов ну прямо таки настаивала, чтобы было больше временных таблиц и переубедить её было невозможно!!! :) ну, а потом…. было очень сильно удивлялась… почему это так долго работает запрос!!! :)
Ещё раз спасибо за статью….
Что бы знать, а не гадать почему запросы работают медленно, как раз и нужно изучать курс по оптимизации :)
Там эта тема разобрана очень подробно.
dbcc shrinkfile (tempdev, ЖелаемыйРазмерФайлаДанныхМб)
dbcc shrinkfile (templog, ЖелаемыйРазмерФайлаЛоговМб)
Возникает вопрос – а какой размер файла данных мне можно пожелать? :) Чем меньше – тем лучше? Есть же какой-то объем, ниже которого файл просто не сожмется? Есть ли смысл сжимать не до минимального размера?
Пожелать можно любой размер, даже если вы укажите 1Мб, файл все равно будет сжать только на столько, на сколько это возможно.
Размер можно вообще не указывать, это не обязательный параметр, в этом случае будет использован размер по умолчанию. Размер по умолчанию это тот размер с которым файл создавался изначально.
Слишком сильно и часто сжимать файлы смысла нет, это и не нужно.
Подробнее про данную команду можно почитать здесь: https://msdn.microsoft.com/ru-ru/library/ms189493.aspx
Спасибо – полезно – это еще раз подтверждает, что человеку дана голова не только шапку носить :)