Что такое код mssql_field_seek

Содержание

FPublisher

Web-технологии: База знаний

Документация PHP

mssql_field_seek

(PHP 4, PHP 5, PECL odbtp:1.1.1-1.1.4)

mssql_field_seek — Seeks to the specified field offset

Описание

bool mssql_field_seek ( resource $result , int $field_offset )

Seeks to the specified field offset. If the next call to mssql_fetch_field() won’t include a field offset, this field would be returned.

Список параметров

The result resource that is being evaluated. This result comes from a call to mssql_query().

The field offset, starts at 0.

Возвращаемые значения

Возвращает TRUE в случае успешного завершения или FALSE в случае возникновения ошибки.

mssql_field_seek

(PHP 4, PHP 5, PECL odbtp >= 1.1.1)

mssql_field_seek — Перемещение к указанному полю

Эта функция УДАЛЕНА в PHP 7.0.0.

Описание

Перемещение к указанному полю. Если в следующем вызове mssql_fetch_field() индекс поля указан не будет, то вернется это поле.

Список параметров

Результирующий набор, полученный из mssql_query() .

Индекс поля. Первое поле имеет индекс 0.

Возвращаемые значения

Возвращает TRUE в случае успешного завершения или FALSE в случае возникновения ошибки.

Примеры

Пример #1 Использование mssql_field_seek() для mssql_fetch_field()

// Соединяемся с MSSQL и выбираем базу
mssql_connect ( ‘MANGO\SQLEXPRESS’ , ‘sa’ , ‘phpfi’ );
mssql_select_db ( ‘php’ );

// Делаем выборку
$query = mssql_query ( ‘SELECT * FROM [php].[dbo].[persons]’ );

// Создаем структуру таблицы
echo ‘

Структура \’persons\’

// Заголовок таблицы
echo ‘

‘ ;
echo ‘ ‘ ;
echo ‘ Имя поля

‘ ;
echo ‘

Тип данных

‘ ;
echo ‘

Максимальная длина

‘ ;
echo ‘

‘ ;
echo ‘

‘ ;

// Выводим все поля
echo ‘

‘ ;

for ( $i = 0 ; $i mssql_num_fields ( $query ); ++ $i ) <
// Забираем информацию по полю, помните, что
// field_offset не должен быть задан.
$field = mssql_fetch_field ( $query );

// Печатаем строку
echo ‘

‘ ;
echo ‘ ‘ . $field -> name . ‘

‘ ;
echo ‘

‘ . strtoupper ( $field -> type ) . ‘

‘ ;
echo ‘

‘ . $field -> max_length . ‘

‘ ;
echo ‘

‘ ;

// Перемещаем внутренний указатель
// к следующей строке
mssql_field_seek ( $query , $i + 1 );
>

echo ‘

‘ ;
echo ‘

‘ ;

// Освобождаем результат
mssql_free_result ( $query );
?>

Что такое код mssql_field_seek

Вы должны подключить файл mysql.h в начале Вашей программы на C:

Вы также должны компоновать программу с математической (для шифрования) и mysqlclient библиотеками:

Включаемые файлы обычно размещены в /usr/include/mysql, а библиотеки могут быть найдены в /usr/lib/mysql.

Если Вы имеете утечку памяти в вашей программе-клиенте, Вы можете компилировать с опцией —with-debug=yes. Это заставит код клиента использовать пакет ‘safe_malloc’ в библиотеке клиентов MySQL. Вызовите TERMINATE(stdout) или my_end(1) в вашей прикладной программе-клиенте перед выходом, чтобы получить список всех утечек памяти. Детали — в файле mysys/safemalloc.c из дистрибутива MySQL.

Рассмотрим простой пример MySQL-клиента, который только выполнит SELECT и выведет все возвращенные строки в STDOUT. В нем использованы далеко не все функции С API, он должен только дать Вам представление о типичном виде программы-клиента.

Клиентские функции

MySQL API использует структуры данных MYSQL (определены в mysql.h) чтобы установить связь с СУБД. Вы можете устанавливать много соединений из одной программы-клиента, однако, каждое соединений должно быть связано с собственной отдельной структурой MYSQL.

После успешного запроса, если данные должны быть возвращены пользователю, набор результатов должен быть передан через функции mysql_use_result или через функцию mysql_store_result. Обе эти функции сохраняют набор результатов в структуре MYSQL_RES. Разница в том, что mysql_store_result передает весь набор результатов в память клиента, а mysql_use_result инструктирует клиента, чтобы он мог получить строку динамически с сервера с каждым обращением к mysql_fetch_row. Имейте в виду, что mysql_use_result занимает ресурсы сервера, и не должен использоваться для интерактивных прикладных программ, где действия пользователя часто непредсказуемы и могут привести к большим задержкам. Обратите внимание также, что Вы можете держать только одно соединение, которое использует mysql_user_result, открытым, и это должно быть последнее созданное соединение. По умолчанию процесс mysqld закроет соединение после тридцати секунд неактивности.

Данные, переданные из набора результатов с помощью mysql_fetch_row, будут помещены в структуру MYSQL_ROW, которая является просто массивом указателей на начало каждого поля.

mysql_affected_rows

Возвращает число строк, на которые воздействует последний UPDATE, DELETE или INSERT.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ:

  • Целое число > 0 показывает число измененных строк.
  • Ноль, если никакие записи не соответствовали предложению WHERE в UPDATE или DELETE.
  • -1, если запрос возвратил ошибку, например, была сделана попытка добавить двойной первичный ключ в течение одного INSERT.

MySQL оптимизирован для случая удаления всех записей в таблице. Побочный эффект этой оптимизации — то, что MySQL возвратится, ноль для числа строк, на которые воздействовал в этой ситуации. Выполнение ‘select count(*) from the_table’ перед удалением всех записей даст Вам значение = на сколько строк воздействовала система, хотя это значение может изменяться между SELECT и DELETE. MySQL 3.20.X не поддерживает блокировку таблицы. Это исправлено в версии 3.21.X

mysql_close

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

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

По умолчанию тайм-аут = 30 секундам для активного запроса и 8 часам для открытого подключения.

mysql_connect

Пытается установить соединение с сервером MySQL, работающем на компьютере host. Значение host может быть сетевым именем или IP адресом. Параметр user задает логин пользователя MySQL, параметр passwd задает пароль для user. ОБРАТИТЕ ВНИМАНИЕ: Не пытайтесь шифровать passwd перед вызовом mysql_connect. Шифрование выполняется автоматически клиентским API.

  • Если host не задан, то подразумевается ‘localhost’.
  • Если user не задан, то подразумевается ‘current user’. Под Windows ODBC, текущий пользователь должен быть определен явно. Под Unix подразумевается текущий логин.
  • Если password не задан, то будут проверены только те записи в таблице пользователей, которые не имеют пароля. Это позволяет db-администратору настроить систему привилегий MySQL так, чтобы пользователь получал различные привилегии в зависимости от того, определен пароль или нет. Иногда полезно.

mysql_connect должен успешно завершиться до каких-либо действий с базой данных.

Вы можете опционально задать первый аргумент mysql_connect как (MYSQL*) 0. Это вынудит C API к автоматическому распределению памяти для структуры подключения и освобождению ее при завершении. Расплатой за это служит то, что Вы не сможете получать сообщения об ошибках из mysql_connect, когда используете эту опцию.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ:

  • mysql, если соединение выполнено успешно.
  • NULL в случае, если связаться не удалось.

mysql_create_db

Создает базу данных, именованную как db на машине, указанной в mysql. MySQL подключение должно быть выполнено с правами пользователя, который имеет право создавать базы данных. Обратитесь к главе «Администрирование пакета» за подробностями о правах доступа.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ:

  • 0, если база данных создана успешно.
  • Не 0, если произошла ошибка. Сообщение об ошибке можно получить с помощью функции mysql_error.

mysql_data_seek

Переходит на указанную строку в наборе результатов запросов. Не может использоваться вместе с mysql_use_result.

mysql_drop_db

Удаляет базу данных с именем, указанным в db на сервере, указанном в mysql. Подключение должно быть выполнено с правами пользователя, который имеет на это право. Обратитесь к главе «Администрирование пакета» за подробностями о правах доступа.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ:

  • 0, если база данных удалена успешно.
  • Не 0, если произошла ошибка. Сообщение об ошибке можно получить с помощью функции mysql_error.

mysql_eof

Возвращает значение != 0, если последний вызов mysql_fetch_row не вернул ничего потому, что достигнут конец набора результатов.

mysql_error

Выводит сообщение об ошибке, если ошибку вернула последняя вызванная функция MySQL. В противном случае возвращает пустую строку.

mysql_fetch_field

Находит тип поля таблицы.

mysql_fetch_lengths

Возвращает длину всех столбцов в наборе результатов запросов. Если Вы планируете получение данных, содержащих \0, Вы должны использовать эту функцию, чтобы получить фактическую длину значения поля.

mysql_fetch_row

Выбирает следующую строку в результате запроса. Возвратит пустой указатель, когда все строки были получены.

mysql_field_seek

Помещает курсор столбца в поле номер field, который должен быть в диапазоне от 0 до mysql_num_fields(MYSQL_RES*)-1.

mysql_free_result

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

mysql_get_client_info

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

mysql_get_host_info

Возвращает имя сервера (заданное в аргументе «host» при вызове mysql_connect).

mysql_get_proto_info

Получает версию протокола, используемую подключением. MySQL поддерживает динамические протоколы, основанные на возможностях клиента. В версии 3.20.X это не делает ничего, но в будущих версиях, эта возможность позволит, например, одному пользователю подключать использование текущего протокола, в то время как другой использует шифрование и сжатие.

mysql_get_server_info

Возвращает версию сервера.

mysql_insert_id

Возвращает ID, сгенерированный для поля AUTO_INCREMENT переменной результата ‘res’.

mysql_list_dbs

Предоставляет простой способ переноса mSQL прикладных программ. Подобно выполнению ‘SHOW databases [ LIKE wild-card ]’, как запроса.

mysql_list_fields

Предоставляет простой способ переноса mSQL прикладных программ. Подобно выполнению ‘SHOW fields [FROM table] [FROM database] [LIKE wild-card]’, как запроса.

mysql_list_processes

Получает список потоков, в настоящее время запущенных на сервере MySQL. Вы должны иметь привилегии process.

mysql_list_tables

Предоставляет простой способ переноса mSQL прикладных программ.

Вызывает как запрос ‘SHOW tables [FROM database]’.

mysql_num_fields

Возвращает количество столбцов (полей) в результате запроса.

mysql_num_rows

mysql_query

Выполняет SQL запрос указанный query к базе данных, указанной в mysql. Эта функция возвращает 0, если запрос выполнен успешно. Результат, отличный от нуля, указывает на ошибку. Обращение к mysql_error выведет текстовое сообщение об ошибке.

Вызов mysql_num_rows даст Вам число строк, возвращенных запросом.

Если Вы имеете поле AUTO_INCREMENT в модифицируемой таблице, и выполняете оператор INSERT, Вы можете получить последнее назначенное значение поля, проверяя mysql_insert_id.

mysql_real_query

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

Вы будете должны использовать эту функцию, если Вы имеете данные, в которые значение \0 входит не как последнее.

mysql_reload

Перезагружают таблицу доступа пользователей, очищает все кэши и закрывает все открытые неиспользуемые таблицы. Должна быть вызвана перед запуском isamchk на любой таблице. Требует, чтобы пользователь имел право на перезагрузку (reload).

mysql_select_db

Пытается соединиться с базой данных, указанной в db, на сервере, указанном в mysql. Сервер СУБД MySQL использует логин и пароль, содержащиеся в mysql, чтобы опознать подключение. Перед использованием mysql_select_db необходимо успешно вызвать mysql_connect.

mysql_select_db должен быть вызван успешно перед попыткой сделать запрос к базе данных. Исключительные ситуации — запросы типа:

mysql_shutdown

Останавливает сервер СУБД MySQL. Пользователь должен иметь право shutdown.

mysql_stat

Возвращает информацию, которую выдает команда ‘mysqladmin version’ в виде строки символов. Эквивалентно опции stat программы mysqladmin. В строку включается информация о простое в секундах, запущенных потоках, запросах, перезагрузках и открытых таблицах.

mysql_store_result

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

mysql_store_result() вернет NULL при ошибке или если инструкция не вернула никаких данных. Вы можете обрабатывать ошибки так:

Илон Маск рекомендует:  Что такое код pdf_add_annotation

Вызов mysql_free_result() должен быть выполнен, чтобы освободить память.

mysql_use_result

То же, что и mysql_store_result(), за исключением того, что результат выдается сервером динамически для каждого вызова mysql_fetch_row(). Эта функция не должна использоваться в интерактивных прикладных программах, так как она связывает сервер. Зато она помогает уменьшить использование памяти на стороне клиента.

Table scan, index scan, index seek

Всем привет! В чем суть алгоритмов?

table scan — последовательный перебор данных
index scan — последовательный перебор по листьям построенного дереа (что по сути тоже само должно быть что и table scan )
index seek — быстрый поиск по дереву.

Чет не могу понять смысл index scan

27.03.2020, 21:06

Три файла,(index.coo, index.doc, index.lex) а что за БД не знаю
Мне дали файловую БД(о-очень много файлов) и три файла: index.coo, index.doc и index.lex. ни doc.

Ошибка SQL «Could not continue scan with NOLOCK due to data movement».
При работе в 1С 7.7 на SQL вылетает ошибка «Could not continue scan with NOLOCK due to data.

ошибка CREATE INDEX
При передаче параметра в CREATE INDEX в столбец выводит ошибку неправильный синтаксис (@sql.

SQL запрос по полю INDEX
Добрый день. Мне нужно работать с базой КЛАДР. Беда в том, что во всех таблицах поле «Индекс» так и.

drop index PRIMARY KEY .
Help plz Kak steret’ index — PRIMARY KEY s pomoshiu SQL? Zaranee blagodaren!

27.03.2020, 21:21 2

Index scan — последовательный перебор по данным индекса, а не данным таблицы.
Кластерный индекс отличается от некластерного индекса тем (одно из отличий), что при его создании происходит копирование данных таблицы и перенос их в индекс (то есть по сути дублирование).

Соответственно, при index scan сама исходная таблица не просматривается, поскольку в этом нет необходимости, а просматривается индекс.

27.03.2020, 21:27 [ТС] 3

Вот это меня и смущает, то есть мы скопировали данные при создании индекса, и ищем по ним. Но ведь это как были данные так и остались. То есть от перемены мест ведь сумма не изменяется?

Или в индексе данные отсортированны стали и там скан по-хитрому происходит? Если так, то как и главное у index seek тогда какой алгоритм?

27.03.2020, 21:47 4

В дополнение: итератор index scan может использоваться как и с некластерным индексами (если select выбирает только колонки, входящие с этот некластерный индекс), так и с кластерными индексами.

Если же запрос данных из таблицы с некластерным индексом будет включать также колонки, которые не входят в состав этого индекса, то в плане запроса появляется еще один итератор: RID Lookup (Row Id lookup).

Добавлено через 4 минуты

Насколько я знаю, данные в индексе отсортированы по полям, входящим в состав ключа индекса.

Добавлено через 19 секунд
Минуту, надо уточнить.

Добавлено через 10 минут
Это да, и кластерный и некластерный индекс упорядочивают свои данные по ключам индекса.
Proof (кластерный индекс):

27.03.2020, 21:47
27.03.2020, 23:43 5

Table Scan — просмотр всех строк таблицы. Неприменимо, если у таблицы есть кластерный индекс

Clustered Index Scan — просмотр всех строк таблицы (кластерный индекс это и есть таблица, а не копия данных таблицы)
Просмотр может быть упорядоченным, т.е. в порядке ключа индекса, либо неупорядоченным — в порядке размещения страниц индекса в БД.

Index Scan — то же самое, что и Clustered Index Scan, только просматривается некластерный индекс.

(Clustered) Index Seek — поиск в индексе по ключу. Может быть точечным, т.е. ищется одна строка. А может сканироваться диапазхон ключей — так называемый Range Scan.

Если интересует алгоритм поиска в и индексе — см. алгоритм поиска в B+ дереве.

Что такое код mssql_field_seek

(row[1] ? row[1] : «NULL»));

/* освободить ресурсы, использовавшиеся результирующим набором */

msqlFreeResult(result); /* закрыть соединение */

Эти программы почти идентичны. Кроме разных имен функций, есть лишь несколько заметных отличий. Сильнее всего бросается в глаза различие в соединении с базой данных, которое проявляется в двух отношениях:

  • В MySQL соединение осуществляется за один шаг, а в mSQL — за два.*
  • Для MySQL требуются имя пользователя и пароль, а для mSQL -нет.

Как указывалось ранее в этой книге, MySQL поддерживает сложную схему авторизации с именами пользователей и паролями. Напротив, в mSQL применяется простая система, использующая ID пользователя процесса, соединяющегося с базой данных. Более надежная схема MySQL гораздо привлекательнее в среде клиент/сервер, но также и значительно более сложна в администрировании. Для разработчиков приложений она означает необходимость передачи в вызове mysql_real_connect() имени пользователя и пароля при работе с MySQL помимо имени сервера, используемого в mSQL.

Первый аргумент API для установления соединения с MySQL может показаться необычным. По сути, это способ отслеживать все вызовы, иначе никак не связанные с соединением. Например, если вы пытаетесь установить соединение, и попытка неудачна, вам нужно получить сообщение о соответствующей ошибке. Однако функция MySQL

mysql_error() требует задания указателя на действующее соединение с базой данных MySQL. Такое соединение обеспечивается изначально созданным нулевым соединением. Однако у вас должна быть действующая ссылка на это значение в течение всего времени существования вашего приложения — вопрос большой важности в более структурированной среде, чем простое приложение вида «соединился, сделал запрос, закрылся». Примеры на C++ далее в этой главе подробнее рассматривают эту тему.

Два другие различия в API относятся к тому, как производятся обработка ошибок и подсчет числа записей в результирующем наборе. API mSQL создает глобальную переменную для хранения сообщений об ошибках. Из-за многопоточности MySQL такая глобальная переменная не смогла бы действовать в его API. Поэтому в нем используется функция mysql_error() для извлечения сообщений об ошибках, связанных с последней ошибкой, порожденной указанным соединением.

API для соединения и обработки ошибок — два пункта, в которых MySQL отличается от mSQL для обеспечения функциональности, отсутствующей в mSQL. Подсчет числа результирующих записей в mSQL делается иным способом для обеспечения лучшего интерфейса, нежели предоставляемый MySQL. А именно: при посылке SQL-запроса в msqlQuery() возвращается число задействованных строк (или -1 в случае ошибки). Таким образом, подсчет измененных строк при обновлении и строк в возвращаемом результирующем наборе при запросе используют одну и ту же парадигму. В MySQL же приходится использовать различные парадигмы. При запросе на получение данных нужно передать результирующий набор функции mysql_nuoi_rows() , чтобы получить число строк в результирующем наборе. При обновлении нужно вызвать другую функцию API, mysql_affected_rows() . В то время как msqlQuery() возвращает число строк, удовлетворивших предложению WHERE при обновлении, mysql_affected_rows() сообщает о числе фактически измененных строк. И наконец, в mSQL есть метод msqlNumRows() , обеспечивающий тот же интерфейс для подсчета результирующего набора, что и в MySQL, но в нем нет аналога для mysql_affected_rows() .

Объектно-ориентированный доступ к базам данных на C++

С API прекрасно работают в процедурном программировании на С. Однако они не очень хорошо вписываются в объектно-ориентированную среду C++. Чтобы показать, как реально использовать в программе эти два API, в оставшейся части главы мы создадим с их помощью C++ API для объектно-ориентированного программирования баз данных.

Рис. 13-1 . Библиотека объектно-ориенитрованного доступа к базе данных

Поскольку мы занимаемся освещением доступа к базам данных MySQL и mSQL, то сосредоточимся на специфичных для MySQL и mSQL темах и не будем пытаться создать совершенный общий C++ API. Работу с MySQL и mSQL описывают три главных понятия: соединение, результирующий набор и строки результирующего набора. Мы будем использовать эти понятия как ядро объектной модели, на которой будет основываться наша библиотека. Рис. 13-1 показывает эти объекты на UML-диаграмме.*

Соединение с базой данных

В любой среде доступ к базе данных начинается с соединения. Как вы видели в первых двух примерах, MySQL и mSQL по-разному представляют одно и то же понятие — соединение с базой данных. Создание нашей объектно-ориентированной библиотеки мы начнем с абстрагирования от этого понятия и создания объекта Connection . Объект Connection должен уметь устанавливать соединение с сервером, выбирать нужную базу данных, посылать запросы и возвращать результаты. Пример 13-3 показывает заголовочный файл, в котором объявлен интерфейс к объекту Connection.

UML — это новый Унифицированный язык моделирования, созданный Гради Бучем, Айваром Якобсоном и Джеймсом Рамбо (Grady Booch, Ivar Jacobson, James Rumbaugh) в качестве нового стандарта для документирования объектно-ориентированного проектирования и анализа.

Пример 13-3. Заголовок класса Connection

Что такое код mssql_field_seek

mssql_field_seek — устанавливает смещение поля.

Описание

int mssql_field_seek (int result, int field_offset)

Ищет специфицированное смещение поля. Если последующий вызов mssql_fetch_field() не будет включать смещение поля, будет возвращено это поле.


Назад Оглавление Вперёд
mssql_field_name Вверх mssql_field_type

Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:

Study & Dev О программировании и не только

Работа с базой данных mysql из c++

November 1, 2007

Для того чтобы использовать возможности mysql сервера из c/c++ вам прежде всего необходимо в свойствах проекта указать местоположение папки include из каталога установки mysql, т.к. в нем находятся h-файлы с прототипами функций и типов данных. Также необходимо подключить к проекту .lib-файлы из каталога Lib.

Методика дальнейшего программирования отличается и зависит от того, как именно вы хотите использовать средства баз данных в приложении: 1 – сервер mysql – является внешней программой и может быть использован для хранения данных нескольких клиентов, второй вариант – предполагает что движок сервера внедряется в код клиентского приложения и обслуживает только его. Начнем с первого варианта.

В коде клиента подключите только mysql.h. Перед ним обязательно должно быть подключен windows.h

Возможно потребуется подключение файла winbase.h.

MySQL API использует структуры данных MYSQL (определены в mysql.h) чтобы установить связь с СУБД. В принципе возможно устанавливать много соединений из одной программы-клиента, но при этом каждое соединение каждое соединений должно быть связано с собственной отдельной структурой struct MYSQL. Которая и объявлена в строке 7.

Строка 8 служит для объявления переменной-ссылки на результат выполнения запроса select.

Строка 9 — объявляет переменную ссылающуюся на одну, конкретную, запись отобранную при переборе в цикле результата выполнения запроса.

Строка 11 содержит объявление функции, выводящей сообщение об ошибке (для этого в строке 12 используется функция mysql_error).

Строка 18 выполняет инициализацию переменной соединения с mysql, и если это не удается, то программа аварийно завершается.

Строка 19 содержит код соединения с СУБД. Обратите внимание на то, что я указал имя машины сервера, а также имя и пароль для доступа к нему. Затем вы задаете номер порта (mysql по-умолчанию исопльзует 3306) далее идут необязательные параметры, которые нас не интересуют.

Строка 21 содержит вызов функции смены текущей базы данных.

Строка 23 содержит запуск запроса отбора информации — всех записей из таблицы students. Для этого используйте mysql_query – данная функция в отличие от одноименной ей в php возвращает не дескриптор результата выполнения а булево-значение – признак успешности операции. Поэтому для доступа к дескриптору результирующего набора строк следует вызвать: mysql_store_result, затем мы печатаем результат выполнения команды, по аналогии с php. Для определения того, сколько было возвращено полей — mysql_num_fields.

Обратите внимание на то что все возвращаемые значения рассматриваюстся как строки текста и переменная типа MYSQL_ROW раскрывается как

здесь отбираются записи начиная с первой – отсчет начинается с нуля в количестве 100, т.е. с номерами: 1-100.

Следующим шагом будет использование серверного курсора – концепция серверных курсоров в том, чтобы не вытягивать данные на клиента – а сохранить на стороне сервера виртуальный указатель на текущую запись в результате выборки – затем по мере того как вы с помощью mysql_fetch_row будете переходить по записям нужные записи будет динамически передаваться с сервера к клиенту. Для этого вместо mysql_store_result используйте функцию mysql_use_result. Например, так:

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

Критически важно: С при использовании mysql_use_result() для инициализации извлечения результирующего набора, клиент получает строки набора с сервера поочередно при повторных вызовах функции mysql_fetch_row(). Поскольку в этом процессе может возникнуть ошибка в соединении, NULL, полученный от mysql_fetch_row(), не всегда означает что мы пролистали все записи. В этом случае вам следует использовать mysql_eof(), чтобы выяснить, что же случилось. mysql_eof() вернет ненулевую величину, если конец результирующего набора был достигнут, и нуль, если произошла ошибка.

Критически важно: Можно держать только одно открытое соединение, которое использует mysql_use_result, и это должно быть последнее созданное соединение. По умолчанию процесс mysqld закроет соединение после тридцати секунд неактивности.

Исследование результата выборки

Так как все поля выборки возвращаются в виде строк, то важным является опредление того какие типы данных они имеют на самом деле и имена полей, для этого используйте функцию:

Которая возвращает определение одного столбца из результирующего набора в виде структуры MYSQL_FIELD. Если вы будете вызывать данную функцию в цикле то переберете все столбцы, если полей больше не остается, функция mysql_fetch_field() вернет NULL.

Каждый раз при выполнении нового запроса SELECT функция mysql_fetch_field() сбрасывается в исходное состояние, чтобы возвращать информацию о первом поле. Следовательно если вы последовательно сделали две выборки и пытаетесь узнать информацию о типах полей в первой выборке, то уже поздно.

Содержимое структуры MYSQL_FIELD содержит не только название поля но и еще множестов характеристик:

По заданному номеру поля fieldnr для поля внутри результирующего набора возвращает определение данного поля в виде структуры MYSQL_FIELD. Эту функцию можно использовать для извлечения определения для произвольного столбца. Величина fieldnr должна находиться в диапазоне от 0 до mysql_num_fields(result)-1.

Данная функция не является “одноразовой” как предыдущая, и мы можем несколько раз вызвать ее для одного или разных res-указателей на mysql_store_result.

В обоих случаях мы можем узнать параметры (характеристики) поля (так в следующем примере определяется то, является ли поле обязательным для ввода):

Существуют макросы упрощающие определение того, что это за поле:

Макрос Примечание
IS_NOT_NULL(flags) Возвращает TRUE, если данное поле определено как NOT NULL
IS_PRI_KEY(flags) Возвращает TRUE, если данное поле является первичным ключом
IS_BLOB(flags) Возвращает TRUE, если данное поле имеет тип BLOB или TEXT

Выполнение команд на изменение данных

Для отправки команды DDL или DML используем туже функцию mysql_query, что и при выборке данных.

Примечание: здесь инструкция содержит ошибку для обработки которой следует анализировать вовсе не значение, которое возвратила функция mysql_query, а значение кода ошибки, возвращаемое mysql_errno. В случае отсутствия ошибок ошибок возвращается 0.

Таблица. Полный перечень функций mysql:

Функция Описание
mysql_affected_rows() Возвращает количество строк, измененных/удаленных/вставленных последним запросом UPDATE, DELETE или INSERT.
mysql_change_user() Переключает пользователя и базу данных для открытого соединения.
mysql_character_set_name() Возвращает название кодировки, установленной для данного соединения.
mysql_close() Закрывает соединение с сервером.
mysql_connect() Создает соединение с сервером баз данных MySQL. Данная функция не рекомендуется; вместо нее следует использовать функцию mysql_real_connect().
mysql_create_db() Создает базу данных. Данная функция не рекомендуется; вместо нее следует использовать команду SQL: CREATE DATABASE.
mysql_data_seek() Ищет произвольную строку в результирующем наборе запроса.
mysql_character_set_name() Возвращает название кодировки, установленной для данного соединения.

Критически важно: Нельзя использовать функции mysql_data_seek(), mysql_row_seek(), mysql_row_tell(), mysql_num_rows() или mysql_affected_rows() для обработки результата, возвращенного функцией mysql_use_result (напоминаю, что это серверный курсор).

Функция Описание
mysql_drop_db() Удаляет базу данных. Эта функция не рекомендуется; вместо нее следует использовать команду SQL DROP DATABASE.
mysql_dump_debug_info() Заставляет сервер записывать отладочную информацию в журнал.
mysql_eof() Определяет, была ли данная строка последней из прочитанных в результирующем наборе данных.
mysql_errno() Возвращает номер ошибки для последней запущенной функции MySQL.
mysql_error() Возвращает сообщение об ошибке для последней запущенной функции MySQL.
mysql_drop_db() Удаляет базу данных. Эта функция не рекомендуется; вместо нее следует использовать команду SQL DROP DATABASE.
mysql_escape_string() Экранирует специальные символы в строке, чтобы ее было возможно использовать в команде SQL.

Примечание: данная функция важна при добавлении в таблицу текстовых значений содержащий ковычки или иные спец. символы. В этом случае ковычки нужно экранировать по типу: ‘ заменять на \’ или \ замятт на \\ — что и делает данная функция.

Функция Описание
mysql_fetch_field() Возвращает тип следующего поля таблицы – помните, что это одноразовая функция.
mysql_fetch_field_direct() Возвращает тип поля таблицы по заданному номеру поля.
mysql_fetch_fields() Возвращает массив структур, содержащих информацию обо всех полях.
mysql_fetch_lengths() Возвращает массив длин всех столбцов в текущей строке.
mysql_fetch_row() Извлекает следующую строку из результирующего набора.
mysql_field_seek() Устанавливает курсор столбцов на заданный столбец.
mysql_field_count() Возвращает количество столбцов в результате для последнего запроса.
mysql_field_tell() Возвращает значение положения курсора поля для последнего вызова mysql_fetch_field().
mysql_free_result() Освобождает память, использованную для результирующего набора.
mysql_get_client_info() Возвращает информацию о версии клиента.
mysql_get_host_info() Возвращает строку, описывающую параметры текущего соединения.
mysql_get_server_version() Возвращает номер версии сервера как целое число (новое с 4.1)
mysql_get_proto_info() Возвращает версию протокола, используемого для данного соединения.
mysql_get_server_info() Возвращает номер версии сервера баз данных.
mysql_info() Возвращает информацию о последнем выполненном запросе.
mysql_init() Выделяет или инициализирует какую-либо структуру MYSQL.
mysql_insert_id() Возвращает идентификатор, сгенерированный для столбца AUTO_INCREMENT предыдущим запросом.

Данная функция возвращает идентификатор, созданный последним запросом, внесшим строку в таблицу с автоинкрементным полем (AUTO_INCREMENT).

Пример для SQL-кода:

Функция Описание
mysql_kill() Уничтожает заданный процесс. Все подсоединения к серверу имеют свои номера, получить информацию о которых можно с помощью команды show processlist. В случае необходимости администратор сервера может «убить» подсоединения с помощью команды KILL номер_соединения.
mysql_list_dbs() Возвращает имена баз данных, совпадающие с простой строкой шаблона.
mysql_list_fields() Возвращает имена полей, совпадающих с простой строкой шаблона.
mysql_list_processes() Возвращает список текущих потоков на сервере.
mysql_list_tables() Возвращает имена таблиц, совпадающих со строкой шаблона.
mysql_num_fields() Возвращает количество столбцов в результирующем наборе.
mysql_num_rows() Возвращает количество строк в результирующем наборе.

Примечание: в случае использования клиентского курсора данная функция возвращает корректное значение, для серверного же только после выборки всех строк функция mysql_num_rows(), будет корректно возвращать количество выбранных строк.

Функция Описание
mysql_options() Устанавливает параметры соединения для mysql_connect().
mysql_ping() Проверяет, работает ли данное соединение с сервером, и восстанавливает соединение при необходимости.
mysql_query() Выполняет SQL-запрос, заданный в виде строки с нулевым символом в конце.

Данный запрос должен состоять из одной команды SQL. Нельзя добавлять к этой команде в качестве завершающих элементов \g – а вот точку с запятой “;” – можно, несмотря на то что документация утверждает противоположное.

Критически важно: Функция mysql_query() не может использоваться для запросов, содержащих двоичные данные; вместо этого необходимо использовать функцию mysql_real_query() (дело в том, двоичные данные могут содержать символ `\0′, который mysql_query() воспринимает как окончание строки запроса).

Для проверки, вернул данный запрос результирующий набор или нет, можно использовать функцию mysql_field_count().

Если запрос был выполнен успешно то возвращается нуль иначе код ошибки.

Функция Описание
mysql_real_connect() Создает соединение с сервером баз данных MySQL. Рекомендуемая функция.
mysql_real_escape_string() Экранирует специальные символы в строке, чтобы обеспечить возможность использования ее в команде SQL, с учетом установленной для данного соединения кодировки.

Данная функция критически важна при выполнении запросов содержащих строки текста (текстовые поля в которых могут встречаться символы ковычек или иные спец.символы).

Строка, указанная в секции from, должна быть длиной length байтов. Необходимо выделить для секции to буфер величиной по меньшей мере length*2+1 байтов (в наихудшем случае каждый символ может потребовать кодировки с использованием двух байтов и, кроме того, необходимо место для концевого нулевого байта).

mssql_field_seek

(PHP 4, PHP 5, PECL odbtp >= 1.1.1)

mssql_field_seek — Seeks to the specified field offset

Description

Seeks to the specified field offset. If the next call to mssql_fetch_field() won’t include a field offset, this field would be returned.

Parameters

The result resource that is being evaluated. This result comes from a call to mssql_query() .

The field offset, starts at 0.

Return Values

Returns TRUE on success or FALSE on failure.

Examples

Example #1 Using mssql_field_seek() on the example for mssql_fetch_field()

// Connect to MSSQL and select the database
mssql_connect ( ‘MANGO\SQLEXPRESS’ , ‘sa’ , ‘phpfi’ );
mssql_select_db ( ‘php’ );

// Send a select query to MSSQL
$query = mssql_query ( ‘SELECT * FROM [php].[dbo].[persons]’ );

// Construct table
echo ‘

Table structure for \’persons\’

// Table header
echo ‘

‘ ;
echo ‘ ‘ ;
echo ‘ Field name

‘ ;
echo ‘

Data type

‘ ;
echo ‘

Max length

‘ ;
echo ‘

‘ ;
echo ‘

‘ ;

// Dump all fields
echo ‘

‘ ;

for ( $i = 0 ; $i mssql_num_fields ( $query ); ++ $i ) <
// Fetch the field information, notice the
// field_offset parameter is not set. See
// the mssql_field_seek call below
$field = mssql_fetch_field ( $query );

// Print the row
echo ‘

‘ ;
echo ‘ ‘ . $field -> name . ‘

‘ ;
echo ‘

‘ . strtoupper ( $field -> type ) . ‘

‘ ;
echo ‘

‘ . $field -> max_length . ‘

‘ ;
echo ‘

‘ ;

// Move the internal seek pointer to the next
// row in the result set
mssql_field_seek ( $query , $i + 1 );
>

echo ‘

‘ ;
echo ‘

‘ ;

// Free the query result
mssql_free_result ( $query );
?>

Упущенные индексы

SQL Server ведёт статистику недостающих/упущенных индексов основываясь на исполняемых запросах, но нельзя полностью доверять советам SQL Server, так как он не знает всей картины и не может её проанализировать. Стоит учесть следующие моменты:

1. Часто бывает так, что SQL Server может советовать создать 5 индексов в таблице, но на деле их можно объединить в один.
2. Нет смысла создавать индексы для запросов, которые были выполнены 1 раз и больше никогда не будут выполнятся или будут, но крайне редко.
3. Относитесь очень критично к этим советам и планируйте каждый создаваемый индекс через данные советы.

Вот код, с помощью которого можно увидеть недостающие индексы во всех таблицах:

Оптимизация SQL-запросов (Часть 1)

В данной статье рассматриваются особенности запросов на выборку данных, виды индексов, использование планов запросов, различные подходы к оптимизации запросов. Во второй части статьи «Оптимизация SQL-запросов (Часть 2)» рассматриваются рекомендации по разработке оптимальной структуры БД.

Введение

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

1. Демонстрационная база данных

Для демонстрации запросов в данном докладе потребуется база данных. Допустим, необходимо автоматизировать следующую предметную область: у торгового предприятия есть различные товары, которые продаются различным заказчикам. Необходимо обеспечить хранение данных по заказам клиентам, включая заказанные товары, и о статусах заказа, развернутых во времени. Создадим упрощенную базу данных.
БД имеет следующую структуру:

База наполнена тестовыми данными:

  • Status — 3 записи
  • Customer — 3 записи
  • Product — 10 записей
  • Order — 3 млн. записей.
  • OrderStatus — 9 млн. записей.
  • OrderProduct — 2,5 млн. записей

2. Запросы на выборку данных

Запросы на выборку данных реализуются с помощью конструкции SELECT языка SQL.
Запрос в MS SQL имеет следующий синтаксис:

2.1. Типы соединений таблиц

Если запрос адресован к нескольким таблицам БД, то выполняется соединение этих таблиц по определенным полям.
Существует несколько типов соединений:
Внутреннее (INNER JOIN)

Внешнее левое/правое (LEFT/RIGHT JOIN)

Перекрестное (CROSS JOIN)
(Используется редко)

2.2. Вложенные запросы

Вложенный запрос представляет собой запрос типа select from select
Пример:

2.3. Короткие и соотнесенные запросы

Пример короткого селекта:

Пример соотнесенного запроса:

В MS SQL короткие и соотнесенные запросы могут быть реализованы с помощью конструкции OUTER/CROSS APPLY.

Существует два типа оператора APPLY: CROSS APPLY и OUTER APPLY. Оператор CROSS APPLY возвращает только строки из внешней таблицы, которые создают результирующий набор из возвращающей табличное значение функции. Оператор OUTER APPLY возвращает и строки, которые формируют результирующий набор, и строки, которые этого не делают, со значениями NULL в столбцах, созданных возвращающей табличное значение функцией.

3. Индексы

3.1. Виды индексов MS-SQL

В MS SQL Индексы могут быть двух типов: кластерные и не кластерные.
Если упрощенно, то кластерный индекс отличается от не кластерного тем, что в листьях этого индекса содержатся не ссылки на записи в таблице, а сами записи. Таким образом, для таблицы допустим только один кластерный индекс.
Скорость доступа к строкам при указании условия where, совпадающего с условием индексирования для кластерного индекса, будет выше, чем при поиске записей по простому индексу.
Если в кластерный индекс включены часто обновляемые поля, то это отрицательно скажется на производительности, т. к. обновления будут приводить к логическому переупорядочиванию данных.
Если из таблицы, имеющей кластерный индекс, часто удаляются записи, то это приводит к сильной фрагментации таблицы.
MS SQL по умолчанию создает кластерные индексы по первичному ключу.

3.2. Ограничения MS SQL при создании индексов

При создании индекса максимальная суммарная длина полей допускается равной 900 байт. Причем индекс может быть создан по полям, типы которых допускают большую длину полей, но при этом хранящиеся данные обязательно должны быть меньше.
Т.е., например, в таблице имеется 2 поля varchar(500) , MSSQL допускает создание индекса при условии, что реальная длина записей по этим полям не превышает 900. При наличии такого индекса в таблице, при попытке вставки (или обновления) данных, если сумма реальных полей будет превышать 500 байт, то будет выдано сообщение об ошибке.
Для хранения каждого символа в типах nvarchar и nchar MS SQL использует 2 байта.

4. Планы запросов

В реляционной СУБД оптимальный план выполнения запроса — это такая последовательность применения операторов реляционной алгебры к исходным и промежуточным отношениям, которое для конкретного текущего состояния БД (её структуры и наполнения) может быть выполнено с минимальным использованием вычислительных ресурсов.

4.1. Анализ плана запроса

Ядро SQL Server Database Engine может показывать, каким образом оно переходит к таблицам и использует индексы для доступа к данным. Это называется выводом плана выполнения. Для проведения анализа медленно выполняемого запроса полезно изучить план выполнения запроса, чтобы определить причину проблемы.
Планы выполнения запросов в MS SQL отображаются cредой SQL Server Management Studio. При этом отображается наилучший план выполнения, используемый ядром Database Engine для отдельных инструкций языка DML и Transact-SQL. В этом плане содержатся сведения о процессе компиляции хранимых процедур и о вызовах хранимых процедур произвольной глубины вложенности. Например, при выполнении инструкции SELECT можно увидеть, что Database Engine выполняет просмотр таблицы для получения данных. Выполнение инструкции SELECT может также показать, что просмотр индекса будет использоваться, если Database Engine определит, что просмотр индекса является наиболее быстрым способом получения данных из таблицы.
Таким образом, выбор оптимального плана во многом зависит от наличия в базе индексов и их оптимальности.

При выполнении запроса в MSSQL есть возможность поиска “отсутствующих” индексов. Т. е. MS SQL подсказывает, какие индексы можно создать, чтобы данный конкретный запрос выполнялся быстрее.
Пример:

Запрос выдает рекомендации на создание индекса:

4.2. Способы применения индекса в планах запроса

Основные типы получения записей индекса это Seek и Scan.
Index Scan получает все записи индекса, указанного в столбце Argument. Если необязательный предикат WHERE:() появится в столбце Argument, то возвращаются только те строки, которые удовлетворяют условию, указанному в этом предикате.
Оператор Index Seek использует возможности поиска по индексам для получения строк из индекса. С самого начала поиск обрабатывает только те строки, которые квалифицированы, и страницы, которые содержат эти квалифицированные строки, поэтому стоимость пропорциональна числу квалифицированных строк и содержащих их страниц, а не к общему числу строк в таблице. Таким образом, поиск является более эффективной стратегией, если мы имеем дело с очень селективным поисковым предикатом; то есть если мы имеем поисковый предикат, который отсекает большую часть таблицы.

4.3. Способы изменения плана

В MS SQL при выполнении запросов можно указать специальные «подсказки» (hint), с помощью которых можно повлиять на план запроса.
Оптимизатор запросов SQL Server обычно автоматически выбирает наилучший план выполнения запроса. Поэтому подсказки, в том числе , рекомендуется использовать только опытным пользователям и администраторам базы данных в случае крайней необходимости.
Примечание. В некоторых СУБД, например Firebird, можно косвенно влиять на план запроса, например добавлением «+0» к полю таблицы. В этом случае оптимизатор перестает использовать индекс.

4.4. Кэширование и повторное использование плана

В SQL Server есть пул памяти, предназначенный для хранения планов выполнения и буферов данных. Процентное соотношение размера пула, выделенного для планов выполнения и буферов данных, динамически изменяется в зависимости от состояния системы. Часть пула памяти, используемого для хранения планов выполнения, называется кэшем процедур.
В SQL Server планы выполнения состоят из следующих основных компонентов.
План запроса. Тело плана выполнения является структурой данных только для чтения, которая предназначена для использования любым числом пользователей. Оно называется планом запроса. План запроса не содержит контекста пользователя.
Контекст выполнения. Для каждого пользователя, который в настоящий момент выполняет запрос, имеется структура данных, которая содержит данные, относящиеся к данному выполнению, например значения параметров. Эта структура данных называется контекстом выполнения. Структуры данных контекста выполнения являются повторно используемыми. Если пользователь выполняет запрос и одна из структур не используется, она повторно инициализируется контекстом нового пользователя.

4.5. Проблема параметров при кэшировании запросов

Если к серверу выполняется несколько однотипных параметризованных запросов, то сервер строит план только для первого запроса, далее этот план попадает в кэш, и остальные запросы выполняются с уже кэшированным планом.
Рассмотрим 2 запроса:

Для выполнения этих запросов используются разные планы, т. к. при построении плана, MS SQL анализирует количество возвращаемых данных.
Если данный запрос сделать параметризованным:

то план запроса будет определятся самым первым запросом.
Это демонстрирует следующий скрипт:

Таким образом, оптимальный план, построенный по первому параметризованному запросу, из-за кэширования будет распространен на остальные запросы, где этот план может оказаться, мягко говоря, не совсем оптимальным.

5. Подходы к оптимизации запросов

5.1. Поиск неоптимальных запросов

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

5.2. Статистика индексов

Для индекса существует понятие плотности распределения. Если каждое значение в таблице уникальное, то плотность будет 1/ . Например, если в таблице 100 записей, то плотность будет равна 1%. Теория говорит, что чем меньше плотность, тем лучше – это увеличивает избирательность, а, следовательно, и ценность построенного индекса.
Например, если колонка содержит только 3 значения, плотность распределения будет равна 33.3%, что показывает бесполезность построения индекса по данному полю. Индексы занимают место на диске и в оперативной памяти и отнимают быстродействие. В идеале, самый лучший индекс имеет плотность распределения равную единице, деленной на количество записей в таблице — все записи уникальны.
При построении индексов, обращайте внимание на плотность распределения – если она превышает 10%, то индекс можно считать бесполезным. Сканирование по таблице в таком случае будет более эффективным.

Для просмотра статистики индекса используется команда:

5.3. Фильтрация в индексах

Фильтруемый индекс — это оптимизированный некластеризованный индекс, особенно подходящий для запросов, осуществляющих выборку из хорошо определенного подмножества данных. Он использует предикат фильтра для индексирования части строк в таблице. Хорошо спроектированный фильтруемый индекс позволяет повысить производительность запросов, а также снизить затраты на обслуживание и хранение индексов по сравнению с полнотабличными индексами.
Пример. Отберем все строки продуктов, где количество больше 9900.

Создадим индекс по полю Quantity:

Создадим фильтрованный индекс:

Кроме того, фильтрованный индекс создается гораздо быстрее.

5.4. Индексы с включенными полями

Индекс с неключевыми столбцами может значительно повысить производительность запроса, когда все столбцы запроса включены в индекс как ключевые или неключевые. Производительность повышается благодаря тому, что оптимизатор запросов может найти все значения столбцов в этом индексе. При этом нет обращения к данным таблиц или кластеризованных индексов, что приводит к меньшему количеству дисковых операций ввода-вывода.
Пример. Допустим, необходимо найти номера и даты заказов по определенному поставщику.
Запрос:

Создаем индекс на поле CustomerId:

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

Создаем индекс с включенными полями:

Время выполнения запроса уменьшается, индекс попадает в план:

5.5. Дополнительные команды при создании индексов

Команда CREATE INDEX имеет дополнительные параметры. Рассмотрим некоторые из них, которые в дальнейшем могут повлиять на производительность запросов.
ASC|DESC
ASC значит что индекс будет построен по возрастанию ключей. DESC соответственно – по убыванию. Эта опция не дает никакой разницы на поиск данных, но оказывает существенное влияние на скорость выполнения ORDER BY опции в запросах.
Пример.

SORT_IN_TEMPDB
Полезна при создании индексов. Эта опция может увеличить производительность системы во время создания индексов. Индексы создаются в два этапа. На первом создается временный набор данных с отсортированными ключами для некластерного индекса. На втором – окончательный результат переносится на место его хранения в базе данных. Без указания данной опции временный результат создается в той же file group, где и будет создан индекс. При указанной опции временный результат будет находиться в базе данных Tempdb. Преимущества: индекс будет менее фрагментирован, временную базу можно поместить на другой диск и тем самым увеличить скорость чтения/записи. Недостаток: требуется больше памяти на дисках и надо уделять дополнительное внимание базе данных Tempdb.

5.6. Оптимизация композитных индексов

В создании композитного (сложного) индекса участвуют несколько полей таблицы. При создании индекса следует обращать внимание на порядок следования полей в индексе.
Например, если создается индекс по полям Field1, Field2, то он может быть применен только в запросе, где в критериях используются оба этих поля. Также этот индекс будет полезен для условий, построенных для одного Field1. Для одного Field2 этот индекс не может быть применен.
Если в дополнение к индексу по полям Field1, Field2 добавить индекс по полям Field2, Field1, то SQL Server при построении плана запроса будет анализировать, какой из них более селективен в применении к ограничениям на условия запроса. Последний момент в построении композитного индекса по полям Field1, Field2 – он не равен сумме индексов по указанным полям. В случае, когда в запросе могут быть использованы оба поля как критерий поиска при раздельных индексах по полям, будет построено пересечение по индексам, что медленнее чем выборка из композитного индекса.
Примечание. В некоторых СУБД, например Firebird, применение нескольких индексов в запросе для одной таблицы ведет к существенному снижению производительности.
Пример. Отберем заказы определенного клиента, начиная с указанной даты.

План показывает сканирование по первичному ключу. MS SQL рекомендует создание композитного индекса по коду поставщика и дате.

Создадим индекс:

Тот же самый запрос стал выполняться быстрее.

Уберем из условия отбор по дате:

Индекс по-прежнему используется.
Теперь вернем условие по дате, но уберем условие по клиенту:

Индекс используется, только вместо более быстрой операции Seek используется Scan.

5.7. Общие рекомендации по проектированию индексов

Большое количество индексов в таблице снижает производительность инструкций INSERT, UPDATE, DELETE и MERGE, потому что при изменении данных в таблице все индексы должны быть изменены соответствующим образом.
Большое число индексов может повысить производительность запросов, которые не изменяют данных, таких как инструкции SELECT, поскольку у оптимизатора запросов будет больший выбор индексов при определении самого быстрого способа доступа.
Индексирование маленьких таблиц может оказаться не лучшим выбором, так как поиск данных в индексе может потребовать у оптимизатора запросов больше времени, чем простой просмотр таблицы. Следовательно, для маленьких таблиц индексы могут вообще не использоваться, но тем не менее их необходимо поддерживать при изменении данных в таблице.

5.8. Выбор типа соединения таблиц

Выбор типа соединения таблиц в запросе (INNER/LEFT/RIGHT) зависит от задачи. Практика показывает, что если в запросе, который подразумевает однозначное соединение одной таблицы с другой, нет большой разницы, использовать INNER или LEFT JOIN. Оптимизатор генерирует для таких запросов одинаковый план.
Пример:

5.9. Рекомендации по оптимизации запросов от Microsoft

Ниже перечислены случаи, когда SQL Server не в состоянии точно вычислить мощность. Это приводит к неточному определению стоимости, что, в свою очередь, может привести к созданию неоптимальных планов запросов. Если избегать применения таких конструкций, можно повысить производительность выполнения запросов. Иногда в таких случаях доступны альтернативные формулировки запросов и другие средства, помогающие решить эту проблему.

  • Запросы с предикатами, которые содержат операторы сравнения столбцов одной и той же таблицы.
  • Запросы с предикатами, использующими операторы, и выполнение одного из следующих условий:
    • отсутствует статистика для столбца, указанного с любой стороны от оператора;
    • распределение значений в статистике неоднородно, а запрос выполняет поиск весьма ограниченного набора значений. Эта ситуация особенно вероятна, если оператор не является оператором равенства (=);
    • предикат использует оператор неравенства (!=) или логический оператор NOT.
  • Запросы с любыми встроенными функциями SQL Server или пользовательскими скалярными функциями, которым в качестве аргументов передаются выражения, отличные от констант.
  • Запросы, в которые включены столбцы, соединяемые по арифметическим операторам или объединением строк.
  • Запросы, которые сравнивают переменные, значения которых в момент компиляции и оптимизации запроса неизвестны.

Для повышения производительности перечисленных типов запросов можно попробовать предпринять следующие меры:
Постройте индексы или статистику для столбцов, участвующих в запросе.
Попробуйте использовать вычисляемые столбцы или перепишите запрос, если он содержит операторы, которые сравнивают или производят арифметические операции над двумя и более столбцами. Например, в следующем запросе сравниваются значения в двух столбцах:

Можно повысить производительность, добавив вычисляемый столбец Col3 к таблице MyTable, который подсчитывает разницу между Col1 и Col2 (Col1 минус Col2). Затем переписать запрос:

Возможно, производительность еще больше повысится, если построить индекс для столбца MyTable.Col3.

Во второй части статьи «Оптимизация SQL-запросов (Часть 2)» рассматриваются рекомендации по разработке оптимальной структуры БД.

Илон Маск рекомендует:  Что такое код strrchr
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL