Блог

Оптимизация запросов

Сори, но некогда писать. Второй день занимаюсь жестокой оптимизацией запросов. Один SELECT запрос выполняется очень часто и из-за пидxxxxxxеского SQL Server приводит к deadlock. Впервые вижу, чтобы SELECT запрос приводит к мертвой блокировке. Я все видел, но чтобы доводить до смерти. Это же банальное чтение данных, какого черта взаимноблокировать чтение.

Только что нашел проблему. Простая перестановка последовательности WHEN в CASE операторе уронила количество сканирований таблицы с 205000 до 18.

Что меня бесит в PHP

В PHP меня бесит то, что в нем конкатенация строк происходит через точку. Когда фигачиш кучу кода на PHP, а потом в том же файле переключаешся на JavaScript и в JavaScript функции пишешь 'Строка 1' . 'Строка 2', то этот код не работает, и ошибок нигде нет. JavaScript не генерирует ошибки, а на фоне большого кода PHP такая небольшая опечатка не кидается в глаза.

Кто знает, нафига в PHP сделали конкатенацию через точку? Лично мне кажется, что это сделано из-за автоматического преобразования. Если написать '22' + '22', то не смотря на то, что перед нами строки, они будут сложены как числа. И иногда это удобно, но все равно точка бесит, потому что во всех остальных языках, которые я исползую, конкатенация идет через символ сложения.

Оптимизация запроса с Датой

Вчера на работе в основном занимался тестированием сайта через различные прокси и оптимизацией запросов. Перед самым новым годом работы нет, поэтому подчищаем сайт.

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

Округление даты и времени в SQL Server

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

Если нужно просто обрубить дату, то можно поступить так:

select dateadd(day, datediff(day, 0, GetDate()), 0)

Где-то я видел пример, в котором автор зачем-то прибавлял и отнимал дату '20000101':

select dateadd(day, datediff(day, '20000101', GetDate()), '20000101')

Результат идентичный предыдущему, а смысла в действии я не понял

Идеальное время

Работая с большой базой данных и с кластером из серверов приложений, я видел уже достаточно много. Но недавно я просто ушел в шок, когда скрипты проверки данных показали, что на один банковский аккаунт было создано два пользователя. Я начал смотреть на записи пользователей и увидел, что они идентичны. Разница только в одном поле - время регистрации.

Пользователь заполнил форму со своими данными и отправил форму серверу. На сервере записи было установлено текущее время регистрации, и по каким-то причином код встал. Что-то подвисло почти на две минуты. У нас есть защита от повторной отправки формы, но каким-то макаром она не сработала и сервер получил второй запрос на регистрацию. Видимо это связано было с тем, что сервер протормозил с первым запросом.

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

Оптимизация или удобство SQL

Сегодня оптимизировал запрос, который до моего вмешательства работал 4 часа. Проблема была в том, что в нем не правильно использовалась функция isnull. Это очень удобная функция, особенно, если использовать ее в блоке SELECT, но ее нужно аккуратно использовать в блоке WHERE.

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

Чтобы проще было следить за тем, что я говорю, давайте представим себе следующий запрос:

Не обновляется база данных

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

Я как и прежде буду просто просить остановить жаркие споры, но не буду закрывать ветки. Новая возможность добавлена для веток, в которых можно мусорить. Например, вчера я создал ветку, в которой кто угодно мог задать вопрос и я отвечал на них. Ветка прожила один день, и я ее закрыл. Подобная ветка будет открыта через некоторое время снова. По ходу дела подобные вещи нужно устраивать чаще, но и нужно иногда останавливать, чтобы я мог передохнуть :).

Но не это самое главное. Я новую маленькую фишку добавлял вчера 3 часа. Тут же возникает вопрос, что я делал все это время? Справедливый вопрос. Вот как все происходило.

Где реально храняться данные

Блин, только выпустил обновление Библии С# и забыл в нем уточнить по поводу простых переменных и структур. Дело в том, что я написал, что их компилятор располагает их в стеке, но это не всегда правда. Так пишут все авторы, но если быть уж совсем точным, то компилятор не обязан располагать переменные в стеке. Обычная практика - он старается делать это. Я специально полез в интернет и увидел кучу статей, в которых пишут про то, что простые переменные будут в стеке.

Возьмем, например, статью .NET: Type Fundamentals еще за 2000 год из самого MSDN. В ней утверждается, что простая переменная будет расположена в стеке:

System.Int32 a = new System.Int32(5); When this statement is compiled, the compiler detects that the System.Int32 type is a value type and optimizes the resulting IL code so that this "object" is not allocated from the heap; instead, this object is placed on the thread's stack in the local variable a.

Библиотеки кода

Когда я программировал в Delphi или на С++, то я ненавидел все эти библиотеки DLL, потому что чтобы выделить какой-то код в отдельный файл, получалось столько геммороя, что зад краснел от просиживания на стуле. Поэтому большинство своих программ я реализовывал в виде единого исполняемого файла.

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

Тест производительности SQL запроса

Мало того, что я обновил программу мониторинга раньше программы сетевых утилит, так я еще и выпустил новый модуль. Все новые модули всегда первыми появляются в программе сетевые утилиты, но этот год исключение. Впервые новый модуль появляется в программе Утилиты Web разработчика.

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

Смысл работы модуля прост – создается куча потоков и программа несколько раз подряд выполняет запросы, чтобы замерить скорость их работы. При этом на экран выводится среднее и максимальное время выполнения запроса, а так же информация об IO операциях сервером. В принципе все очень просто, но удобная утилита под подобные вещи никогда не помешает.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне