mysqlpro/ 500 0 0 0 10643272074 5704 5mysqlpro/charset.htm 600 0 0 431476 10643272542 10132 Глава 10. Поддержка наборов символов

Глава 10. Поддержка наборов символов

MySQL включает поддержку набора символов, которая дает возможность Вам сохранить данные, использующие ряд наборов символов и выполнять сравнения согласно ряду объединений. Вы можете определять наборы символов на уровне сервера, базы данных, таблицы и столбца. MySQL поддерживает использование наборов символов для типов хранения MyISAM, MEMORY, NDBCluster и InnoDB.

Эта глава обсуждает следующие темы

Проблемы набора символов воздействуют на хранение данных, но также и на связь между программами пользователя и сервером MySQL. Если Вы хотите, чтобы программа пользователя связалась с сервером, использующим набор символов, отличный от значения по умолчанию, вы должны будете указать, который именно. Например, чтобы использовать utf8 Unicode, выдайте эту инструкцию после соединения с сервером:

SET NAMES 'utf8';

10.1. Наборы символов и объединения вообще

Набор символов представляет собой множество символов и их кодов. Объединение задает набор правил для сравнения символов в наборе символов. Давайте сделаем различие явным с помощью примера.

Предположите, что мы имеем алфавит с четырьмя символами: A, B, a, b. Мы даем каждому символу номер: A = 0, B = 1, a = 2, b = 3. Символ A имеет номер 0, который the кодирует символ A, комбинация из всех четырех символов и их кодирования как раз и есть набор символов.

Предположите, что мы хотим сравнивать два строковых значения, A и B. Самый простой способ сделать это состоит в том, чтобы рассмотреть кодирование: 0 = A и 1 = B. Поскольку 0 меньше чем 1, мы говорим, что A меньше чем B. Что мы только что сделали? Применили объединение к нашему набору символов. Объединение задает набор правил (только одно правило в этом случае). Самым простым из всех возможных объединений является двоичное объединение.

Но что, если мы хотим считать, что нижний регистр и прописные буквы эквивалентны? Мы имели бы по крайней мере два правила: (1) обрабатывает символы нижнего регистра a и b как эквивалент A и B, (2) затем сравнивает кодирование. Мы называем это объединением без учета регистра. Это немного более сложно, чем двоичное объединение.

В реальной жизни большинство наборов символов имеет много символов: не только A и B, а целые алфавиты, иногда много алфавитов или восточные системы записи с тысячами символов, наряду с многими специальными символами и знаками препинания. Также в реальной жизни большинство объединений имеет много правил, не только для того, чтобы отличить регистр символов, но также и для того, чтобы отличить диакритические знаки. А также для многосимвольных отображений (типа правил в немецком языке).

MySQL может делать эти дела для Вас:

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

10.2. Наборы символов и объединения в MySQL

Сервер MySQL может поддерживать много наборов символов. Чтобы вносить в список доступные наборы символов, используйте инструкцию SHOW CHARACTER SET. Ниже приведен кусок вывода этой команды:

mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset  | Description                 | Default collation   | Maxlen |
+----------+-----------------------------+---------------------+--------+
|     big5 | Big5 Traditional Chinese    | big5_chinese_ci     | 2      |
|     dec8 | DEC West European           | dec8_swedish_ci     | 1      |
|    cp850 | DOS West European           | cp850_general_ci    | 1      |
|      hp8 | HP West European            | hp8_english_ci      | 1      |
|    koi8r | KOI8-R Relcom Russian       | koi8r_general_ci    | 1      |
|   latin1 | cp1252 West European        | latin1_swedish_ci   | 1      |
|   latin2 | ISO 8859-2 Central European | latin2_general_ci   | 1      |
|     swe7 | 7bit Swedish                | swe7_swedish_ci     | 1      |
|    ascii | US ASCII                    | ascii_general_ci    | 1      |
|     ujis | EUC-JP Japanese             | ujis_japanese_ci    | 3      |
|     sjis | Shift-JIS Japanese          | sjis_japanese_ci    | 2      |
|   hebrew | ISO 8859-8 Hebrew           | hebrew_general_ci   | 1      |
|   tis620 | TIS620 Thai                 | tis620_thai_ci      | 1      |
|    euckr | EUC-KR Korean               | euckr_korean_ci     | 2      |
|    koi8u | KOI8-U Ukrainian            | koi8u_general_ci    | 1      |
|   gb2312 | GB2312 Simplified Chinese   | gb2312_chinese_ci   | 2      |
|    greek | ISO 8859-7 Greek            | greek_general_ci    | 1      |
|   cp1250 | Windows Central European    | cp1250_general_ci   | 1      |
|      gbk | GBK Simplified Chinese      | gbk_chinese_ci      | 2      |
|   latin5 | ISO 8859-9 Turkish          | latin5_turkish_ci   | 1      |
...

Любой заданный набор символов всегда имеет по крайней мере одно объединение, но может иметь и несколько объединений. Чтобы вносить в список объединения для набора символов, используйте инструкцию SHOW COLLATION. Например, чтобы увидеть объединения для набора символов latin1, используйте эту инструкцию, чтобы найти те имена объединения, которые начинаются с latin1:

mysql> SHOW COLLATION LIKE 'latin1%';
+--------------------+---------+----+---------+----------+---------+
| Collation          | Charset | Id | Default | Compiled | Sortlen |
+--------------------+---------+----+---------+----------+---------+
| latin1_german1_ci  | latin1  |  5 |         |          | 0       |
| latin1_swedish_ci  | latin1  |  8 | Yes     | Yes      | 1       |
| latin1_danish_ci   | latin1  | 15 |         |          | 0       |
| latin1_german2_ci  | latin1  | 31 |         | Yes      | 2       |
| latin1_bin         | latin1  | 47 |         | Yes      | 1       |
| latin1_general_ci  | latin1  | 48 |         |          | 0       |
| latin1_general_cs  | latin1  | 49 |         |          | 0       |
| latin1_spanish_ci  | latin1  | 94 |         |          | 0       |
+--------------------+---------+----+---------+----------+---------+

Объединения в latin1 имеют следующие значения:

Объединение Значение
latin1_german1_ciGerman DIN-1
latin1_swedish_ciSwedish/Finnish
latin1_danish_ciDanish/Norwegian
latin1_german2_ciGerman DIN-2
latin1_binBinary according to latin1 encoding
latin1_general_ci Multilingual (Western European)
latin1_general_csMultilingual (ISO Western European), case sensitive
latin1_spanish_ciModern Spanish

Объединения имеют эти общие характеристики:

10.3. Определение наборов символов и объединений

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

CHARACTER SET используется в предложениях, которые определяют набор символов. CHARSET может использоваться как синоним для CHARACTER SET.

10.3.1. Набор символов и объединение на стороне сервера

Сервер MySQL имеет набор символов и объединение сервера. Они могут быть установлены при запуске и изменены во время выполнения.

Первоначально, набор символов и объединение зависят от параметров, которые Вы используете, когда запускаете mysqld . Вы можете использовать --character-set-server для набора символов. Наряду с этим, Вы можете добавлять --collation-server для объединения. Если Вы не определяете набор символов, считается, что задано --character-set-server=latin1. Если Вы определяете только набор символов (например, latin1), но не задаете объединение, считается, что задано --character-set-server=latin1 --collation-server=latin1_swedish_ci, потому что latin1_swedish_ci заданное по умолчанию объединение для latin1. Следовательно, следующий три команды все имеют тот же самый эффект:

shell> mysqld
shell> mysqld --character-set-server=latin1
shell> mysqld --character-set-server=latin1 \
                 --collation-server=latin1_swedish_ci

Один способ изменят параметры настройки: перекомпиляция. Если Вы хотите изменять заданный по умолчанию набор символов сервера и объединение при формировании из исходных текстов, используйте: --with-charset и --with-collation в качестве параметров для configure. Например:

shell> ./configure --with-charset=latin1

Или:

shell> ./configure --with-charset=latin1 \
                      --with-collation=latin1_german1_ci

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

Текущий набор символов и объединение сервера могут быть определены из значений переменных системы character_set_server и collation_server. Эти переменные могут быть изменены во время выполнения.

10.3.2. Набор символов и объединение базы данных

Каждая база данных имеет набор символов и объединение базы данных. Инструкции CREATE DATABASE и ALTER DATABASE имеет факультативные предложения для определения набора символов базы данных и объединения:

CREATE DATABASE db_name
       [[DEFAULT] CHARACTER SET charset_name]
       [[DEFAULT] COLLATE collation_name]

ALTER DATABASE db_name
      [[DEFAULT] CHARACTER SET charset_name]
      [[DEFAULT] COLLATE collation_name]

Ключевое слово SCHEMA может использоваться вместо DATABASE.

Все параметры базы данных сохранены в текстовом файле db.opt, который может быть найден в каталоге баз данных.

Предложения CHARACTER SET и COLLATE делают возможным создать базы данных с различными наборами символов и объединениями на том же самом сервере MySQL.

Пример:

CREATE DATABASE db_name CHARACTER SET latin1
       COLLATE latin1_swedish_ci;

MySQL выбирает набор символов и объединение базы данных следующим способом:

Набор символов базы данных и объединение используется как значения по умолчанию, если набор символов таблицы и объединение не определен в инструкции CREATE TABLE. Они не имеют никакой другой цели.

Набор символов и объединение для заданной по умолчанию базы данных может быть определено из значений переменных системы character_set_database и collation_database. Сервер устанавливает эти переменные всякий раз, когда заданная по умолчанию база данных изменяется. Если не имеется никакой заданной по умолчанию базы данных, переменные имеют то же самое значение, что и соответствующие переменные системы уровня сервера: character_set_server и collation_server.

10.3.3. Набор символов и объединение таблицы

Каждая таблица имеет набор символов таблицы и объединение. Инструкции CREATE TABLE и ALTER TABLE имеют факультативные предложения для определения набора символов таблицы и объединения:

CREATE TABLE tbl_name
             (column_list)
       [[DEFAULT] CHARACTER SET charset_name]
       [COLLATE collation_name]]
ALTER TABLE tbl_name
      [[DEFAULT] CHARACTER SET charset_name]
      [COLLATE collation_name]

Пример:

CREATE TABLE t1 ( ... ) CHARACTER SET latin1 COLLATE latin1_danish_ci;

MySQL выбирает набор символов таблицы и объединение следующим способом:

Набор символов таблицы и объединение используется как значения по умолчанию, если набор символов столбца и объединение не определен в индивидуальных определениях столбца. Набор символов и объединение таблицы представляют собой расширения MySQL, не имеется ничего такого в стандарте SQL.

10.3.4. Набор символов и объединение столбца

Каждый символьный столбец (то есть, столбец типа CHAR, VARCHAR или TEXT) имеет набор символов и объединение столбца. Синтаксис определения столбца имеет факультативные предложения для определения набора символов и объединения столбца:

col_name {CHAR | VARCHAR | TEXT}
(col_length)
[CHARACTER SET charset_name]
[COLLATE collation_name]

Пример:

CREATE TABLE Table1
       (column1 VARCHAR(5) CHARACTER SET latin1
       COLLATE latin1_german1_ci);

MySQL выбирает набор символов столбца и объединение следующим способом:

Предложения CHARACTER SET и COLLATE стандартны для SQL.

10.3.5. Набор символов и объединение символьных строковых литералов

Каждый символьный строковый литерал имеет набор символов и объединение.

Символьный строковый литерал может иметь факультативный набор символов и предложение COLLATE:

[_charset_name]'string'
[COLLATE collation_name]

Пример:

SELECT 'string';
SELECT _latin1'string';
SELECT _latin1'string' COLLATE latin1_danish_ci;

Для простой инструкции SELECT 'string', строка имеет набор символов и объединение, определенное переменными системы character_set_connection и collation_connection.

Выражение _charset_name формально названо introducer. Это сообщает синтаксическому анализатору, что строка предположительно соответствует набору символов X. Поскольку было много путаницы в прошлом, следует особо подчеркнуть, что introducer не вызывает никаких преобразований, это строго сигнал, который не изменяет значение строки. Introducer также допустим перед стандартным шестнадцатеричным литералом и числовой шестнадцатеричной литеральной записью (x'literal' и 0xnnnn)>.

Пример:

SELECT _latin1 x'AABBCC';
SELECT _latin1 0xAABBCC;

MySQL определяет набор символов литерала и объединение следующим способом:

Пример:

Набор символов и предложение COLLATE выполнены согласно стандарту SQL

introducer указывает набор символов для следующей строки, но не изменяет того, как синтаксический анализатор выполняет обработку Escape внутри строки. Escape всегда интерпретируются синтаксическим анализатором согласно набору символов, заданному в character_set_connection.

Следующие примеры показывают, что происходит обработка Escape, используя character_set_connection даже в присутствии introducer. Примеры используют SET NAMES (который изменяет character_set_connection) и отображает возникающие в результате строки, использующие HEX(), чтобы было видно точное строковое содержимое.

Пример 1:

mysql> SET NAMES latin1;
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT HEX('├а\n'), HEX(_sjis'├а\n');
+-------------+------------------+
| HEX('├а\n') | HEX(_sjis'├а\n') |
+-------------+------------------+
|        E00A | E00A             |
+-------------+------------------+
1 row in set (0.00 sec)

Здесь ├а (шестнадцатеричное значение E0) сопровождается \n, управляющей последовательностью для новой строки. Управляющая последовательность интерпретируется, используя значение character_set_connection latin1, чтобы произвести литерал newline (новая строка, шестнадцатеричное значение 0A). Это случается даже для второй строки. То есть introducer _sjis не воздействует на обработку синтаксического анализатора Escape.

Пример 2:

mysql> SET NAMES sjis;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT HEX('├а\n'), HEX(_latin1'├а\n');
+-------------+--------------------+
| HEX('├а\n') | HEX(_latin1'├а\n') |
+-------------+--------------------+
|      E05C6E |             E05C6E |
+-------------+--------------------+
1 row in set (0.04 sec)

Здесь character_set_connection равен sjis, набор символов в котором последовательность ├а сопровождается \ (шестнадцатеричные значения 05 и 5C), допустимый многобайтовый символ. Следовательно, первые два байта строки интерпретируются как одиночный символ sjis, и \ не обрабатывается как символ ESC. Следующий n (шестнадцатеричное значение 6E) не интерпретируется как часть управляющей последовательности. Таким образом, introducer _latin1 не воздействует на обработку Escape.

10.3.6. Национальный набор символов

Стандарт SQL определяет NCHAR или NATIONAL CHAR как способ указать, что столбец CHAR должен использовать некоторый предопределенный набор символов. MySQL 5.1 использует utf8 как этот предопределенный набор символов. Например, эти объявления типа данных эквивалентны:

CHAR(10) CHARACTER SET utf8
NATIONAL CHARACTER(10)
NCHAR(10)

Эти тоже взаимозаменяемы:

VARCHAR(10) CHARACTER SET utf8
NATIONAL VARCHAR(10)
NCHAR VARCHAR(10)
NATIONAL CHARACTER VARYING(10)
NATIONAL CHAR VARYING(10)

Вы можете использовать N'literal', чтобы создать строку в национальном наборе символов. Эти две инструкции эквивалентны:

SELECT N'some text';
SELECT _utf8'some text';

10.3.7. Примеры назначения набора символов и объединения

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

Пример 1: определение таблицы и столбца

CREATE TABLE t1 (c1 CHAR(10) CHARACTER SET latin1 COLLATE latin1_german1_ci)
       DEFAULT CHARACTER SET latin2
       COLLATE latin2_bin;

Здесь мы имеем столбец с набором символов latin1 и объединением latin1_german1_ci. Определение явно, так что это просто. Обратите внимание, что не имеется никакой проблемы с сохранением столбца latin1 в таблице latin2.

Пример 2: определение таблицы и столбца

CREATE TABLE t1 (c1 CHAR(10) CHARACTER SET latin1)
       DEFAULT CHARACTER SET latin1
       COLLATE latin1_danish_ci;

На сей раз мы имеем столбец с набором символов latin1 и заданным по умолчанию объединением. Хотя это могло бы показаться естественным, заданное по умолчанию объединение не принимается из уровня таблицы. Вместо этого, поскольку заданное по умолчанию объединение для latin1 обязательно latin1_swedish_ci, столбец c1 имеет объединение latin1_swedish_ci (не latin1_danish_ci).

Пример 3: определение таблицы и столбца

CREATE TABLE t1 (c1 CHAR(10))
       DEFAULT CHARACTER SET latin1
       COLLATE latin1_danish_ci;

Мы имеем столбец с заданными по умолчанию набором символов и объединением. В этой ситуации MySQL проверяет уровень таблицы, чтобы определить набор символов столбца и объединение. Следовательно, набор символов для столбца c1 latin1 и объединение latin1_danish_ci.

Пример 4: определение базы данных, таблицы и столбца

CREATE DATABASE d1 DEFAULT CHARACTER SET latin2
       COLLATE latin2_czech_ci; USE d1;
CREATE TABLE t1 (c1 CHAR(10));

Мы создаем столбец без того, чтобы определить набор символов и объединение. Мы также не определяем набор символов и объединение в уровне таблицы. В этой ситуации MySQL проверяет уровень базы данных, чтобы определить параметры настройки таблицы, которые с этого времени станут параметрами настройки столбца. Следовательно, набор символов для столбца c1 latin2 и объединение latin2_czech_ci.

10.3.8. Совместимость с другими СУБД

Для совместимости с MaxDB эти две инструкции те же самые:

CREATE TABLE t1 (f1 CHAR(N) UNICODE);
CREATE TABLE t1 (f1 CHAR(N)
       CHARACTER SET ucs2);

10.4. Наборы символов и объединения подключения

Несколько переменных системы для наборов символов и объединений касаются взаимодействия пользователя с сервером. Некоторые из них были упомянуты в более ранних разделах:

Дополнительный набор символов и объединения переменные системы включаются в трафике обработки для подключения. Каждый пользователь имеет связанные с подключением переменные системы набора символов и объединения.

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

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

Имеются две инструкции, которые воздействуют на наборы символов подключения:

SET NAMES 'charset_name'
SET CHARACTER SET charset_name

SET NAMES указывает то, какой набор символов применяет пользователь, чтобы послать инструкции SQL на сервер. Таким образом, SET NAMES 'cp1251' сообщает, что будущие входящие сообщения от этого пользователя находятся в наборе символов cp1251. Это также определяет набор символов, который сервер должен использовать для посылки результатов обратно пользователю. Например, это указывает то, какой набор символов использовать для значений столбца, если Вы используете инструкцию SELECT.

Инструкция SET NAMES 'x' эквивалентна этим трем инструкциям:

SET character_set_client = x;
SET character_set_results = x;
SET character_set_connection = x;

Установка character_set_connection в x также устанавливает collation_connection к заданному по умолчанию объединению для x. Чтобы определять специфическое объединение для наборов символов, используйте факультативное предложение COLLATE:

SET NAMES 'charset_name'
    COLLATE 'collation_name'

SET CHARACTER SET подобен SET NAMES, но устанавливает character_set_connection и collation_connection в character_set_database и collation_database. Инструкция SET CHARACTER SET x эквивалентна этим трем инструкциям:

SET character_set_client = x;
SET character_set_results = x;
SET collation_connection = @@collation_database;

Установка collation_connection также устанавливает character_set_connection к набору символов, связанному с объединением (эквивалент выполнения SET character_set_connection = @@character_set_database).

Когда пользователь соединяется, он посылает серверу имя набора символов, который требуется использовать. Сервер использует имя, чтобы установить переменные системы character_set_client, character_set_results и character_set_connection. В действительности сервер выполняет операцию SET NAMES, использующую имя набора символов.

С клиентом mysql нет необходимости выполнять SET NAMES каждый раз при запуске, если Вы хотите использовать набор символов, отличный от значения по умолчанию. Вы можете добавить опцию --default-character-set в операторной строке mysql или в Вашем файле опций. Например, следующий файл опций, устанавливает изменения трех переменных наборов символов к koi8r каждый раз, когда Вы вызываете mysql:

[mysql]
default-character-set=koi8r

Если Вы используете клиент mysql с поддержкой реконнекта (что вообще-то не рекомендуется), предпочтительно использовать команду charset, а не SET NAMES. Например:

mysql> charset utf8
Charset changed

Команда charset выдает инструкцию SET NAMES, а также изменяет заданный по умолчанию набор символов, который используется, если mysql повторно соединяется после того, как подключение прервалось.

Пример: Предположите, что column1 определен как CHAR(5) CHARACTER SET latin2. Если Вы не говорите SET NAMES или SET CHARACTER SET, то для then for SELECT column1 FROM t сервер посылает обратно все значения column1, использующий набор символов, который пользователь определил, когда соединялся. С другой стороны, если Вы говорите SET NAMES 'latin1' или SET CHARACTER SET latin1 перед выдачей инструкции SELECT, сервер преобразовывает значения latin2 в latin1 только перед посылкой результатов обратно. Преобразование может быть с потерями, если имеются символы, которые не представлены в обоих наборах символов.

Если Вы не хотите, чтобы сервер выполнил любое преобразование наборов результатов, установите character_set_results в NULL:

SET character_set_results = NULL;

Обратите внимание: в настоящее время UCS-2 не может использоваться как набор символов пользователя, это означает, что SET NAMES 'ucs2' не работает.

Чтобы видеть значения переменных системы набора символов и объединения, которые обращаются к Вашему подключению, используйте эти инструкции:

SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';

10.5. Проблемы объединения

Следующие разделы излагают различные аспекты объединений набора символов.

10.5.1. Использование COLLATE в SQL-инструкциях

С предложением COLLATE Вы можете отменять любое заданное по умолчанию объединение для сравнения. COLLATE может использоваться в различных частях инструкций SQL. Имеются некоторые примеры:

10.5.2. Старшинство предложения COLLATE

Предложение COLLATE имеет высокое старшинство (выше, чем ||), так следующие два выражения эквивалентны:

x || y COLLATE z
x || (y COLLATE z)

10.5.3. Оператор BINARY

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

mysql> SELECT 'a' = 'A';
    -> 1
mysql> SELECT BINARY 'a' = 'A';
    -> 0
mysql> SELECT 'a' = 'a ';
    -> 1
mysql> SELECT BINARY 'a' = 'a ';
    -> 0

BINARY str сокращение для CAST(str AS BINARY).

Атрибут BINARY на символьных определениях столбца имеет различный эффект. Символьному столбцу, определенному с атрибутом BINARY, назначено двоичное объединение набора символов столбца. Каждый набор символов имеет двоичное объединение. Например, двоичное объединение для набора символов latin1: latin1_bin, так что, если набор символов по умолчанию таблицы latin1, эти два столбца определены эквивалентно:

CHAR(10) BINARY
CHAR(10) CHARACTER SET latin1 COLLATE latin1_bin

Эффект BINARY как атрибута столбца отличается от эффекта до MySQL 4.1. Прежде BINARY помечал столбец, который обрабатывался как двоичная строка, то есть строка байтов, которая не имеет никакого набора символов или объединения, что отличается от не двоичной символьной строки, которая имеет двоичное объединение. Для обоих типов строк сравнения основаны на числовых значениях строкового модуля, но для не двоичных строк, модулем является символ, и некоторые наборы символов позволяют многобайтовые символы.

Использование CHARACTER SET binary на определении столбца CHAR, VARCHAR или TEXT заставляет столбец обрабатываться как двоичный тип данных. Например, следующие пары определений эквивалентны:

CHAR(10) CHARACTER SET binary
BINARY(10)
VARCHAR(10) CHARACTER SET binary
VARBINARY(10)
TEXT CHARACTER SET binary
BLOB

10.5.4. Некоторые специальные случаи, где определение объединения сложно

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

SELECT x FROM T ORDER BY x;
SELECT x FROM T WHERE x = x;
SELECT DISTINCT x FROM T;

Однако, когда включаются многократные операнды, может иметься неоднозначность. Например:

SELECT x FROM T WHERE x = 'Y';

Это должно использовать объединение из столбца x или от литерала строки 'Y'?

Стандарт SQL решает такие вопросы, применяя правило coercibility. В основном это означает: раз x и 'Y' имеют объединения, которое объединение имеет приоритет? Это может быть трудно решить, но следующие правила покрывают большинство ситуаций:

Предшествующие значения coercibility текущие для MySQL 5.1.

Эти правила решают неоднозначности следующим способом:

Пример:

column1 = 'A' Использует объединение column1
column1 = 'A' COLLATE x Использует объединение 'A' COLLATE x
column1 COLLATE x = 'A' COLLATE y Ошибка

Функция COERCIBILITY() может использоваться, чтобы определить coercibility строкового выражения:

mysql> SELECT COERCIBILITY('A' COLLATE latin1_swedish_ci);
    -> 0
mysql> SELECT COERCIBILITY(VERSION());
    -> 3
mysql> SELECT COERCIBILITY('A');
    -> 4

10.5.5. Объединения должны быть для правильного набора символов

Каждый набор символов имеет одно или большее количество объединений, но каждое объединение связано с одним и только одним набором символов. Следовательно, следующая инструкция вызывает сообщение об ошибке, потому что объединение latin2_bin не допустимо с набором символов latin1:

mysql> SELECT _latin1 'x' COLLATE latin2_bin;
ERROR 1253 (42000): COLLATION 'latin2_bin' is not valid
for CHARACTER SET 'latin1'

10.5.6. Пример эффекта объединения

Предположите, что столбец X в таблице T имеет эти значения столбца latin1:

Muffler
M├╝ller
MX Systems
MySQL

Предположите также, что значения столбца получены, используя следующую инструкцию:

SELECT X FROM T ORDER BY X COLLATE collation_name;

Следующая таблица показывает возникающий в результате порядок значений, если мы используем ORDER BY с различными объединениями:

latin1_swedish_ci latin1_german1_cilatin1_german2_ci
MufflerMufflerM├╝ller
MX SystemsM├╝llerMuffler
M├╝llerMX SystemsMX Systems
MySQLMySQLMySQL

Символ, который вызывает различные порядки сортировки в этом примере: U с двумя точками сверху, который в Германии известен как U-umlaut.

10.6. Операции, на которые воздействует поддержка набора символов

Этот раздел описывает операции, которые берут во внимание информацию о наборе символов.

10.6.1. Строки результата

MySQL имеет много операторов и функций, которые возвращают строку. Этот раздел отвечает на вопрос: каков набор символов и объединение у такой строки?

Для простых функций, которые берут строку ввода и возвращают строковый результат как вывод, набор символов и объединение вывода такие же, как таковые у входного значения. Например, UPPER(X) возвращает строку, чья символьная строка и объединение являются такими же, как X. Это относится к INSTR(), LCASE(), LOWER(), LTRIM(), MID(), REPEAT(), REPLACE(), REVERSE(), RIGHT(), RPAD(), RTRIM(), SOUNDEX(), SUBSTRING(), TRIM(), UCASE() и UPPER().

Обратите внимание: функция REPLACE(), в отличие от всех других функций, всегда игнорирует объединение строкового ввода и выполняет чувствительное к регистру сравнение.

Если строковый ввод или функциональный результат является двоичной строкой, она не имеет никакого набора символов или объединения. Это может быть проверено, используя функции CHARSET() и COLLATION(), которые вернут binary, чтобы указать, что их параметр двоичная строка:

mysql> SELECT CHARSET(BINARY 'a'), COLLATION(BINARY 'a');
+---------------------+-----------------------+
| CHARSET(BINARY 'a') | COLLATION(BINARY 'a') |
+---------------------+-----------------------+
|              binary |                binary |
+---------------------+-----------------------+

Для операций, которые объединяют многостроковые вводы и возвращают одиночный строковый вывод, правила соединения частей стандарта SQL дают определение объединения результата:

Например, с CASE ... WHEN a THEN b WHEN b THEN c COLLATE X END возникающее в результате объединение X. То же самое для UNION, ||, CONCAT(), ELT(), GREATEST(), IF() и LEAST().

Для операций, которые преобразовываются в символьные данные, набор символов и объединение строк результата операции определены переменными системы character_set_connection и collation_connection. Это применяется только для CAST(), CONV(), FORMAT(), HEX() и SPACE().

Если Вы не уверены относительно набора символов или объединения результата, возвращенного строковой функцией, Вы можете использовать функцию CHARSET() или COLLATE(), чтобы выяснить:

mysql> SELECT USER(), CHARSET(USER()), COLLATION(USER());
+----------------+-----------------+-------------------+
| USER()         | CHARSET(USER()) | COLLATION(USER()) |
+----------------+-----------------+-------------------+
| test@localhost | utf8            | utf8_general_ci   |
+----------------+-----------------+-------------------+

10.6.2. CONVERT() и CAST()

CONVERT() обеспечивает способ преобразовать данные между различными наборами символов. Синтаксис:

CONVERT(expr USING transcoding_name)

В MySQL имена перекодировки такие же, как соответствующие имена наборов символов.

Примеры:

SELECT CONVERT(_latin1'M├╝ller' USING utf8);
INSERT INTO utf8table (utf8column)
SELECT CONVERT(latin1field USING utf8) FROM latin1table;

CONVERT(... USING ...) выполнено согласно стандарту SQL.

Вы можете также использовать CAST(), чтобы преобразовать строку в иной набор символов. Синтаксис:

CAST(character_string AS
     character_data_type
     CHARACTER SET charset_name)

Пример:

SELECT CAST(_latin1'test' AS CHAR CHARACTER SET utf8);

Если Вы используете CAST() без того, чтобы определить CHARACTER SET, возникающие в результате набор символов и объединение определены переменными системы character_set_connection и collation_connection. Если Вы используете CAST() с CHARACTER SET X, возникающие в результате набор символов и объединение X и заданное по умолчанию объединение для X.

Вы не можете использовать предложение COLLATE внутри CAST(), но Вы можете использовать это снаружи. То есть CAST(... COLLATE ...) запрещено, но CAST(...) COLLATE ... допустимо.

Пример:

SELECT CAST(_latin1'test' AS CHAR CHARACTER SET utf8) COLLATE utf8_bin;

10.6.3. Инструкции SHOW и INFORMATION_SCHEMA

Несколько инструкций SHOW обеспечивают дополнительную информацию о наборе символов. Они включают SHOW CHARACTER SET, SHOW COLLATION, SHOW CREATE DATABASE, SHOW CREATE TABLE и SHOW COLUMNS. Эти инструкции описаны здесь кратко.

INFORMATION_SCHEMA имеет несколько таблиц, которые содержат информацию, подобную отображаемой инструкциями SHOW. Например, таблицы CHARACTER_SETS и COLLATIONS содержат информацию, отображаемую SHOW CHARACTER SET и SHOW COLLATION.

Команда SHOW CHARACTER SET показывает все доступные наборы символов. Требуется факультативное предложение LIKE, которое указывает, которым именам набора символов соответствовать. Например:

mysql> SHOW CHARACTER SET LIKE 'latin%';
+---------+-----------------------------+-------------------+--------+
| Charset | Description                 | Default collation | Maxlen |
+---------+-----------------------------+-------------------+--------+
| latin1  | cp1252 West European        | latin1_swedish_ci | 1      |
| latin2  | ISO 8859-2 Central European | latin2_general_ci | 1      |
| latin5  | ISO 8859-9 Turkish          | latin5_turkish_ci | 1      |
| latin7  | ISO 8859-13 Baltic          | latin7_general_ci | 1      |
+---------+-----------------------------+-------------------+--------+

Вывод SHOW COLLATION включает все доступные наборы символов. Требуется факультативное предложение LIKE, которое указывает, которым именам объединения соответствовать. Например:

mysql> SHOW COLLATION LIKE 'latin1%';
+-------------------+---------+----+---------+----------+---------+
| Collation         | Charset | Id | Default | Compiled | Sortlen |
+-------------------+---------+----+---------+----------+---------+
| latin1_german1_ci | latin1  |  5 |         |          | 0       |
| latin1_swedish_ci | latin1  |  8 | Yes     | Yes      | 0       |
| latin1_danish_ci  | latin1  | 15 |         |          | 0       |
| latin1_german2_ci | latin1  | 31 |         | Yes      | 2       |
| latin1_bin        | latin1  | 47 |         | Yes      | 0       |
| latin1_general_ci | latin1  | 48 |         |          | 0       |
| latin1_general_cs | latin1  | 49 |         |          | 0       |
| latin1_spanish_ci | latin1  | 94 |         |          | 0       |
+-------------------+---------+----+---------+----------+---------+

SHOW CREATE DATABASE отображает инструкцию CREATE DATABASE, которая создала эту базу данных:

mysql> SHOW CREATE DATABASE test;
+----------+-----------------------------------------+
| Database | Create Database                         |
+----------+-----------------------------------------+
| test     | CREATE DATABASE `test` /*!40100 DEFAULT |
|          | CHARACTER SET latin1 */                 |
+----------+-----------------------------------------+

Если никакое предложение COLLATE не показывается, заданное по умолчанию объединение для набора символов применяется.

SHOW CREATE TABLE подобна, но отображает инструкцию CREATE TABLE, чтобы создать данную таблицу. Определения столбца указывают любые спецификации набора символов, и параметры таблицы включают информацию набора символов.

Инструкция SHOW COLUMNS отображает объединения столбцов таблицы когда вызывается как SHOW FULL COLUMNS. Столбцы с типами данных CHAR, VARCHAR или TEXT имеют объединения. Числовые и другие не-символьные типы не имеют никакого объединения (обозначены NULL как значение Collation). Например:

mysql> SHOW FULL COLUMNS FROM person\G
*************************** 1. row ***************************
Field: id
Type: smallint(5) unsigned
Collation: NULL
Null: NO
Key: PRI
Default: NULL
Extra: auto_increment
Privileges: select, insert, update, references
Comment:
*************************** 2. row ***************************
Field: name
Type: char(60)
Collation: latin1_swedish_ci
Null: NO
Key:
Default:
Extra:
Privileges: select, insert, update, references
Comment:

Набор символов не отображается, но подразумевается именем объединения.

10.7. Поддержка Unicode

MySQL 5.1 поддерживает два набора символов для сохранения данных Unicode:

В UCS-2 (двоичное представление Unicode) каждый символ представляется двухбайтным Unicode-кодом со старшим байтом сначала. Например: LATIN CAPITAL LETTER A имеет код 0x0041, и это сохранено как двухбайтовая последовательность 0x00 0x41. CYRILLIC SMALL LETTER YERU (Unicode 0x044B) сохранена как двухбайтовая последовательность 0x04 0x4B. Для получения символов Unicode и их кодов, пожалуйста, обратитесь к Unicode Home Page (http://www.unicode.org).

В настоящее время UCS-2 не может использоваться как набор символов пользователя, это означает, что SET NAMES 'ucs2' не работает.

UTF-8 (трансформируемое представление Unicode) представляет собой альтернативный способ сохранить Unicode данные. Это выполнено согласно RFC 3629. Идея относительно UTF-8 состоит в том, что различные символы Unicode, используя последовательности байтов различных длин:

RFC 3629 описывает последовательности кодирования, которые берут от одного до четырех байтов. В настоящее время MySQL-поддержка для UTF-8 не включает последовательности с четырьмя байтами. Старый стандарт для кодирования UTF-8 задан RFC 2279 и описывает UTF-8-последовательности, которые берут от одного до шести байтов. RFC 3629 объявляет RFC 2279 устаревшим, по этой причине последовательности с пятью и шестью байтами больше не используются.

Совет: чтобы сохранять пробел а UTF-8, используйте VARCHAR вместо CHAR. Иначе MySQL должен резервировать по три байта для каждого символа в столбце CHAR CHARACTER SET utf8, потому что это максимальная возможная длина. Например, MySQL должен резервировать 30 байтов для столбца CHAR(10) CHARACTER SET utf8.

10.8. UTF-8 для метаданных

Метаданные представляют собой такие данные, которые описывают базу данных в противоположность данным, являющимся содержанием базы данных. Таким образом, имена столбцов, базы данных, пользователей, версия и большинство строк-результатов SHOW как раз и являются именно метаданными. Это также истинно для содержания таблиц в INFORMATION_SCHEMA, потому что те таблицы по определению содержат информацию относительно объектов базы данных.

Представление метаданных должно удовлетворять эти требованиям:

Чтобы удовлетворять обоим требованиям, MySQL сохраняет метаданные в наборе символов Unicode, а именно в UTF-8. Это не вызывает никаких сбоев, если Вы никогда не используете не латинские или символы с диакритическим знаком. Но если Вы это делаете, Вы должны знать, что метаданные находятся в UTF-8.

Требования метаданных означают, что возвращаемые значения функций USER(), CURRENT_USER(), SESSION_USER(), SYSTEM_USER(), DATABASE() и VERSION() имеют по умолчанию набор символов UTF-8.

Сервер устанавливает переменную системы character_set_system к имени набора символов метаданных:

mysql> SHOW VARIABLES LIKE 'character_set_system';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| character_set_system | utf8  |
+----------------------+-------+

Хранение метаданных, использующих Unicode, не означает, что сервер возвращает заголовки столбцов и результатов функции DESCRIBE в наборе символов character_set_system по умолчанию. Когда Вы используете SELECT column1 FROM t, имя column1 непосредственно возвращено в наборе символов, определенном значением переменной системы character_set_results, которая имеет значение по умолчанию latin1. Если Вы хотите, чтобы сервер передал результаты метаданных в ином наборе символов, используйте инструкцию SET NAMES, чтобы выполнять преобразование набора символов. SET NAMES устанавливает character_set_results и другие связанные переменные системы. В качестве альтернативы программа пользователя может выполнять преобразование после получения результата с сервера. Это более эффективно для пользователя, но эта опция не всегда доступна для всей клиентуры.

Если character_set_results установлен в NULL, никакое преобразование не выполняется и метаданные возвращаются, используя первоначальный набор символов (набор, обозначенный character_set_system).

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

Если Вы используете (например) функцию USER() для сравнения или назначения внутри одиночной инструкции, можете не волноваться. MySQL выполняет автоматическое преобразование для Вас.

SELECT * FROM Table1 WHERE USER() = latin1_column;

Это работает потому, что содержание latin1_column автоматически преобразовано в UTF-8 перед сравнением.

INSERT INTO Table1 (latin1_column) SELECT USER();

Это работает потому, что содержание USER() автоматически преобразовано в latin1 перед назначением. Автоматическое преобразование полностью все же не выполнено, но должно работать правильно в более поздней версии.

Хотя автоматическое преобразование не в SQL стандарте, документ SQL-стандарта говорит, что каждый набор символов (в терминах обеспечиваемых символов) подмножество Unicode. Поэтому объединение для Unicode может применяться для сравнения с не-Unicode строками.

10.9. Преобразование набора символов столбца

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

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

ALTER TABLE t MODIFY col1 CHAR(50) CHARACTER SET greek;

Предположите, что таблица t имеет не двоичный столбец col1, определенный как CHAR(50) CHARACTER SET latin1 , но Вы хотите преобразовывать это, чтобы использовать utf8 так, чтобы Вы могли сохранять значения из многих языков. Следующая инструкция выполняет это:

ALTER TABLE t MODIFY col1 CHAR(50) CHARACTER SET utf8;

Преобразование может быть с потерями, если столбец содержит символы, которые не содержатся в обоих наборах символов.

Специальный случай происходит, если Вы имеете старые таблицы из MySQL 4.0 или ранее, где не двоичный столбец содержит значения, которые фактически закодированы в наборе символов, отличном от заданного по умолчанию набора символов сервера. Например, прикладная программа могла бы сохранить значения sjis в столбце даже при том, что заданный по умолчанию набор символов MySQL latin1. Возможно преобразовать столбец, чтобы использовать соответствующий набор символов, но дополнительный шаг требуется. Предположите, что заданный по умолчанию набор символов сервера был latin1, а col1 определен как CHAR(50), но содержит значения в sjis. Первый шаг должен преобразовать столбец в двоичный тип данных, который удаляет существующую информацию набора символов без того, чтобы выполнить любое символьное преобразование:

ALTER TABLE t MODIFY col1 BINARY(50);

Следующий шаг должен преобразовать столбец в не двоичный тип данных с соответствующим набором символов:

ALTER TABLE t MODIFY col1 CHAR(50) CHARACTER SET sjis;

Эта процедура требует, чтобы таблица не изменилась с инструкциями типа INSERT или UPDATE после обновления до MySQL 4.1 или позже. В этом случае MySQL сохранил бы новые значения в столбце, использующем latin1, и столбец будет содержать смесь значений sjis и latin1, а значит не может быть преобразован правильно.

Если Вы определили атрибуты при создании столбца первоначально, Вы должны также определить их, при изменении таблицы с помощью ALTER TABLE. Например, если Вы определили NOT NULL и явное значение DEFAULT, Вы должны также обеспечить их в инструкции ALTER TABLE. Иначе возникающее в результате определение столбца не будет включать эти атрибуты.

10.10. Наборы символов и объединения, которые поддерживает MySQL

MySQL поддерживает свыше 70 объединений для более 30 наборов символов. Этот раздел указывает, которые наборы символов MySQL поддерживает. Имеется один подраздел для каждой группы связанных наборов символов. Для каждого набора символов, перечислены допустимые объединения.

Вы можете всегда вносить в список доступные наборы символов и их заданные по умолчанию объединения инструкцией SHOW CHARACTER SET:

mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+
| Charset  | Description                 | Default collation   |
+----------+-----------------------------+---------------------+
| big5     | Big5 Traditional Chinese    | big5_chinese_ci     |
| dec8     | DEC West European           | dec8_swedish_ci     |
| cp850    | DOS West European           | cp850_general_ci    |
| hp8      | HP West European            | hp8_english_ci      |
| koi8r    | KOI8-R Relcom Russian       | koi8r_general_ci    |
| latin1   | cp1252 West European        | latin1_swedish_ci   |
| latin2   | ISO 8859-2 Central European | latin2_general_ci   |
| swe7     | 7bit Swedish                | swe7_swedish_ci     |
| ascii    | US ASCII                    | ascii_general_ci    |
| ujis     | EUC-JP Japanese             | ujis_japanese_ci    |
| sjis     | Shift-JIS Japanese          | sjis_japanese_ci    |
| hebrew   | ISO 8859-8 Hebrew           | hebrew_general_ci   |
| tis620   | TIS620 Thai                 | tis620_thai_ci      |
| euckr    | EUC-KR Korean               | euckr_korean_ci     |
| koi8u    | KOI8-U Ukrainian            | koi8u_general_ci    |
| gb2312   | GB2312 Simplified Chinese   | gb2312_chinese_ci   |
| greek    | ISO 8859-7 Greek            | greek_general_ci    |
| cp1250   | Windows Central European    | cp1250_general_ci   |
| gbk      | GBK Simplified Chinese      | gbk_chinese_ci      |
| latin5   | ISO 8859-9 Turkish          | latin5_turkish_ci   |
| armscii8 | ARMSCII-8 Armenian          | armscii8_general_ci |
| utf8     | UTF-8 Unicode               | utf8_general_ci     |
| ucs2     | UCS-2 Unicode               | ucs2_general_ci     |
| cp866    | DOS Russian                 | cp866_general_ci    |
| keybcs2  | DOS Kamenicky Czech-Slovak  | keybcs2_general_ci  |
| macce    | Mac Central European        | macce_general_ci    |
| macroman | Mac West European           | macroman_general_ci |
| cp852    | DOS Central European        | cp852_general_ci    |
| latin7   | ISO 8859-13 Baltic          | latin7_general_ci   |
| cp1251   | Windows Cyrillic            | cp1251_general_ci   |
| cp1256   | Windows Arabic              | cp1256_general_ci   |
| cp1257   | Windows Baltic              | cp1257_general_ci   |
| binary   | Binary pseudo charset       | binary              |
| geostd8  | GEOSTD8 Georgian            | geostd8_general_ci  |
| cp932    | SJIS for Windows Japanese   | cp932_japanese_ci   |
| eucjpms  | UJIS for Windows Japanese   | eucjpms_japanese_ci |
+----------+-----------------------------+---------------------+

10.10.1. Наборы символов Unicode

MySQL имеет два набора символов Unicode. Вы можете сохранять текст приблизительно для 650 языков, используя эти наборы символов.

Обратите внимание, что в объединениях ucs2_roman_ci и utf8_roman_ci I и J считаются эквивалентными, равно как и пара U и V.

Объединения ucs2_hungarian_ci и utf8_hungarian_ci были добавлены в MySQL 5.1.5.

MySQL осуществляет объединение utf8_unicode_ci согласно Unicode Collation Algorithm (UCA), описанному на http://www.unicode.org/reports/tr10/. Объединение использует version-4.0.0 UCA weight keys: http://www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txt. Следующее обсуждение использует utf8_unicode_ci, но это также верно и для ucs2_unicode_ci.

В настоящее время объединение utf8_unicode_ci имеет только частичную поддержку для Unicode Collation Algorithm. Некоторые символы все же не обеспечиваются. Также полностью не обеспечивается объединение меток. Это воздействует прежде всего на вьетнамский и некоторые малораспространенные языки в России, типа Udmurt, Tatar, Bashkir и Mari.

Старшее свойство в utf8_unicode_ci: это поддерживает расширения, то есть когда один символ сравнивается как равный комбинациям других символов. Например, в немецком и некоторых других языках ├Я равен ss.

utf8_general_ci объединение, которое не поддерживает расширения. Это может делать только взаимно-однозначные сравнения между символами. Это означает, что сравнения для объединения utf8_general_ci быстрее, но немного менее правильные, чем сравнения для utf8_unicode_ci.

Например, следующие равенства верны в utf8_general_ci и в utf8_unicode_ci:

├Д = A
├Ц = O
├Ь = U

Различие между объединениями: это является истинным для utf8_general_ci:

├Я = s

В то время, как это истинно для utf8_unicode_ci:

├Я = ss

MySQL осуществляет специфические для языка объединения для набора символов utf8 только, если упорядочение с utf8_unicode_ci не работает хорошо для языка. Например, utf8_unicode_ci работает прекрасно для German и French, а значит нет никакой потребности создавать специальные объединения utf8 для этих двух языков.

utf8_general_ci также удовлетворителен для German и French за исключением того, что ├Я равно s, но ss. Если это приемлемо для вашей прикладной программы, то применяйте utf8_general_ci, потому что это быстрее. Иначе, используйте utf8_unicode_ci, потому что это более точно.

utf8_swedish_ci, подобно другим специфическим для языка объединениям utf8, получен из utf8_unicode_ci с дополнительными правилами языка. Например, в Swedish следующие связи хранения, которые неприменимы для German или French:

├Ь = Y < ├Ц

Объединения utf8_spanish_ci и utf8_spanish2_ci соответствуют современному и традиционному испанскому, соответственно. В обоих объединениях ├▒ (n-tilde) отдельный символ между n и o. Кроме того, для традиионного испанского ch отдельный символ между c и d, а ll отдельный символ между l и m

10.10.2. Западноевропейские наборы символов

Западноевропейские наборы символов покрывают большинство западноевропейских языков, типа French, Spanish, Catalan, Basque, Portuguese, Italian, Albanian, Dutch, German, Danish, Swedish, Norwegian, Finnish, Faroese, Icelandic, Irish, Scottish и English.

10.10.3. Центральноевропейские наборы символов

MySQL обеспечивает поддержку для наборов символов, используемых в Czech Republic, Slovakia, Hungary, Romania, Slovenia, Croatia и Poland.

10.10.4. Южноевропейские и ближневосточные наборы символов

Южныоевропейские и ближневосточные наборы символов, обеспечиваемые MySQL, включают Armenian, Arabic, Georgian, Greek, Hebrew и Turkish.

10.10.5. Балтийские наборы символов

Балтийские наборы символов охватывают Estonian, Latvian и Lithuanian.

10.10.6. Наборы символов кириллицы

Наборы символов и объединения кириллицы для использования с Belarusian, Bulgarian, Russian и Ukrainian.

10.10.7. Азиатские наборы символов

Азиатские наборы символов, которые поддерживает пакет, включают Chinese, Japanese, Korean и Thai. Они могут быть усложнены. Например, китайские наборы должны учесть тысячи различных символов.

10.10.7.1. Набор символов cp932

А на кой вообще нужен cp932?

В MySQL набор символов sjis соответствует Shift_JIS определенному IANA, который поддерживает символы JIS X0201 и JIS X0208 (см. http://www.iana.org/assignments/character-sets).

Однако, значение SHIFT JIS как описательный термин стало очень неопределенным, и это часто включает расширения Shift_JIS, которые определены различными поставщиками. Короче, больше стандартов, хороших и разных!

Например, SHIFT JIS, использованный в Japanese Windows, представляет расширение Shift_JIS от Microsoft, и его точное название Microsoft Windows Codepage: 932 или cp932. В дополнение к символам, обеспечиваемым Shift_JIS, cp932 поддерживает символы расширения типа специальных и изюранных символов NEC и расширенных символов IBM.

Много японских пользователей испытали проблемы при использовании этих символов расширения. Эта проблема складывается из следующих факторов:

Набор символов MySQL cp932 разработан, чтобы решить эти проблемы.

Поскольку MySQL поддерживает преобразование набора символов, важно отделить IANA Shift_JIS от cp932: это два различных набора символов, потому что они обеспечивают разные правила преобразования.

А в чем разница между cp932 и sjis?

Набор символов cp932 отличается от sjis следующим:

Для некоторых символов, преобразование в и из ucs2 отлично для sjis и cp932. Следующие таблицы иллюстрируют эти различия.

Преобразование в ucs2:

sjis /cp932Значение sjis -> ucs2 преобразование cp932 ->ucs2 преобразование
5C005C005C
7E007E007E
815C20152015
815F005CFF3C
8160301CFF5E
816120162225
817C2212FF0D
819100A2FFE0
819200A3FFE1
81CA00ACFFE2

Преобразование из ucs2:

ucs2 значение ucs2 -> sjis преобразование ucs2 -> cp932 преобразование
005C815F5C
007E7E7E
00A281913F
00A381923F
00AC81CA3F
2015815C815C
201681613F
2212817C3F
22253F8161
301C81603F
FF0D3F817C
FF3C3F815F
FF5E3F8160
FFE03F8191
FFE13F8192
FFE23F81CA

Пользователи любых японских наборов символов должны знать, что использование опций --character-set-client-handshake (или --skip-character-set-client-handshake) имеет важный эффект.

10.11. MySQL 5 FAQ: поддержка наборов символов CJK

Этот набор вопросов происходит из опыта поддержки MySQL в обработке запросов относительно проблем кириллицы и CJK (Chinese-Japanese-Korean).

10.11.1: Я вставил символы CJK в мою таблицу. Почему SELECT отображает их как символы ??

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

10.11.2: Какие китайские (GB) наборы символов понимает MySQL?

MySQL поддерживает два общих варианта GB GB ( Guojia Biaozhun или национального эталона) набора символов, которые являются официальными в КНР: gb2312 и gbk. Иногда люди пробуют вставлять символы gbk в gb2312, и это работает в большинстве случаев, потому что gbk является надмножеством gb2312, но в конечном счете они пробуют вставлять старые китайские символы, и это не работает (см. Глюк #16072).

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

10.11.3: Какие проблемы я должен знать при работе с китайским набором символов Big5?

MySQL поддерживает набор символов Big5, который является общим в Гонконге и на Tайване (Republic of China). MySQL big5 в действительности кодовая страница Microsoft 950, которая очень похожа на оригинальный набор символов big5. Пакет перешео на этот набор символов, начиная с MySQL 4.1.16/5.0.16 (в результате Глюка #12476). Например, следующие инструкции работают в текущих версиях MySQL, но не в старых версиях:

mysql> CREATE TABLE big5 (BIG5 CHAR(1) CHARACTER SET BIG5);
Query OK, 0 rows affected (0.13 sec)
mysql> INSERT INTO big5 VALUES (0xf9dc);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM big5;
+------+
| big5 |
+------+
| хл║  |
+------+
1 row in set (0.02 sec)

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

10.11.4: Почему японские преобразования набора символов терпят неудачу?

MySQL поддерживает наборы символов sjis, ujis, cp932 и eucjpms так же, как Unicode. Общая потребность состоит в том, чтобы преобразоваться между наборами символов. Например, есть Unix-сервер (обычно с sjis или ujis) и Windows-клиент (а здесь почти всегда встречается cp932).

В следующей таблице преобразования столбец ucs2 представляет источник, а столбцы sjis, cp932, ujis и eucjpms представляют адресатов, то есть последние 4 столбца обеспечивают шестнадцатеричный результат, когда Вы используете CONVERT(ucs2) или назначаете столбец, содержащий значение ucs2, столбцу в sjis, cp932, ujis или eucjpms.

Имя символа ucs2sjis cp932ujis eucjpms
BROKEN BAR00A6 3F3F8FA2C3 3F
FULLWIDTH BROKEN BARFFE4 3FFA553F 8FA2
YEN SIGN00A53F 3F203F
FULLWIDTH YEN SIGNFFE5 818F818FA1EF 3F
TILDE007E7E 7E7E7E
OVERLINE203E3F 3F203F
HORIZONTAL BAR2015815C 815CA1BD A1BD
EM DASH20143F 3F3F3F
REVERSE SOLIDUS005C 815F5C5C 5C
FULLWIDTH ""FF3C3F 815F3F A1C0
WAVE DASH301C8160 3FA1C1 3F
FULLWIDTH TILDEFF5E3F 81603F A1C1
DOUBLE VERTICAL LINE2016 81613FA1C2 3F
PARALLEL TO22253F 81613F A1C2
MINUS SIGN2212817C 3FA1DD 3F
FULLWIDTH HYPHEN-MINUSFF0D 3F817C 3FA1DD
CENT SIGN00A28191 3FA1F1 3F
FULLWIDTH CENT SIGNFFE0 3F81913F A1F1
POUND SIGN00A38192 3FA1F2 3F
FULLWIDTH POUND SIGNFFE1 3F81923F A1F2
NOT SIGN00AC 81CA3FA2CC 3F
FULLWIDTH NOT SIGNFFE23F 81CA3FA2CC

Теперь рассмотрите эту часть таблицы:

ucs2 sjiscp932
NOT SIGN00AC 81CA3F
FULLWIDTH NOT SIGNFFE2 3F81CA

Это означает, что MySQL преобразовывает NOT SIGN (Unicode U+00AC) в sjis 0x81CA и в cp932 3F (3F как раз и есть знак вопроса (?), то есть то, что всегда используется, когда преобразование не может выполняться.

10.11.5: Что я должен делать, если я хочу преобразовывать SJIS 81CA в cp932?

Имеются серьезные жалобы относительно этого: много людей предпочли бы свободное преобразование так, чтобы 81CA (NOT SIGN) в sjis становился 81CA (FULLWIDTH NOT SIGN) в cp932. Изменение для этого поведения планируется.

10.11.6: Как MySQL представляют знак Yen (┬е)?

Проблема возникает потому, что некоторые версии японских наборов символов (sjis и euc) обрабатывают 5C как reverse solidus (\ он же backslash), а другие обрабатывают это как знак йены (┬е).

MySQL следует только за одной версией JIS (Japanese Industrial Standards). В MySQL 5C всегда обратный слэш (\).

10.11.7: MySQL планирует делать отдельный набор символов, где 5C представляет знак йены?

Это одно из возможных решений для проблемы знака йены, однако, это не будет в MySQL 5.1 или 5.2.

10.11.8: Какие проблемы я должен знать при работе с корейскими наборами символов в MySQL?

В теории, хотя есть несколько версий набора символов euckr (Extended Unix Code Korea), только одна проблема была отмечена.

Мы используем ASCII-вариант EUC-KR, в котором код 0x5c указывает REVERSE SOLIDUS, \ вместо KS-Roman-варианта EUC-KR, в котором код 0x5c определяет WON SIGN(тВй). Это означает, что Вы не можете преобразовывать Unicode U+20A9 в euckr:

mysql> SELECT CONVERT('тВй' USING euckr) AS euckr,
    ->        HEX(CONVERT('тВй' USING euckr)) AS hexeuckr;
+-------+----------+
| euckr | hexeuckr |
+-------+----------+
| ?     | 3F       |
+-------+----------+
1 row in set (0.00 sec)

Графическая корейская диаграмма MySQL здесь: http://d.udm.net/bar/~bar/charts/euckr_korean_ci.html.

10.11.9: Почему я получаю сообщения об ошибке "Data truncated"?

Для иллюстрации мы создадим таблицу с одним столбцом Unicode (ucs2) и другим Chinese (gb2312):

mysql> CREATE TABLE ch
    ->        (ucs2 CHAR(3) CHARACTER SET ucs2,
    ->        gb2312 CHAR(3) CHARACTER SET gb2312);
Query OK, 0 rows affected (0.05 sec)

Мы пробуем помещать редкий символ ц▒М в обоих столбцах:

mysql> INSERT INTO ch VALUES ('Aц▒МB','Aц▒МB');
Query OK, 1 row affected, 1 warning (0.00 sec)

Имеется предупреждение. Давайте посмотрим, что там случилось:

mysql> SHOW WARNINGS;
+---------+------+---------------------------------------------+
| Level   | Code | Message                                     |
+---------+------+---------------------------------------------+
| Warning | 1265 | Data truncated for column 'gb2312' at row 1 |
+---------+------+---------------------------------------------+
1 row in set (0.00 sec)

Так что это предупреждение только относительно столбца gb2312.

mysql> SELECT ucs2, HEX(ucs2), gb2312, HEX(gb2312) FROM ch;
+-------+--------------+--------+-------------+
| ucs2  | HEX(ucs2)    | gb2312 | HEX(gb2312) |
+-------+--------------+--------+-------------+
| Aц▒МB | 00416C4C0042 | A?B    | 413F42      |
+-------+--------------+--------+-------------+
1 row in set (0.00 sec)

Имеются несколько вещей, которые надлежит понять здесь:

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

  2. Символ ц▒М не находится в наборе символов gb2312. Мы рассматривали эту проблему ранее.

  3. По общему признанию сообщение вводит в заблуждение. В этом случае не было никакого усечения: а произошла тривиальная замена символа на вопросительный знак. Авторы уже имели недовольство относительно этого сообщения (см. Глюк #9337 ). Но пока они придумывают кое-что получше, имейте в виду что сообщение 2165 может означать ряд вещей.

  4. С SQL_MODE=TRADITIONAL имелось бы сообщение об ошибке, но вместо ошибки 2165 Вы будете видеть: ERROR 1406 (22001): Data too long for column 'gb2312' at row 1.

10.11.10: Почему мой внешний GUI-интерфейс или окно просмотра не отображает символы CJK правильно в моей прикладной программе, использующей Access, PHP или другой API?

Получите прямое подключение к серверу, применяя клиент mysql (в Windows: mysql.exe), и попытайтесь выполнить тот же самый запрос там. Если mysql отвечает правильно, то проблема может быть в том, что Ваш интерфейс прикладной программы требует инициализации. Используйте mysql, чтобы понять, какой набор символов это использует с помощью инструкции SHOW VARIABLES LIKE 'char%';. Если Вы используете Access, то Вы наиболее вероятно соединяетесь с MyODBC. В этом случае Вы должны проверить конфигурацию ODBC. Если, например, Вы используете big5, Вы ввели бы SET NAMES 'big5'. Обратите внимание, что ; не требуется в этом случае. Если Вы используете ASP, Вы могли бы добавить SET NAMES в код. Имеется пример, который работал в прошлом:

<%
Session.CodePage=0
Dim strConnection
Dim Conn
strConnection="driver={MySQL ODBC 3.51 Driver}; \
               server=server;uid=username;" \
               & "pwd=password; \
               database=database; \
               stmt=SET NAMES 'big5';"
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open strConnection
%>

Аналогичным способом, если Вы используете любой набор символов, другой, чем latin1 с Connector/NET, Вы должны определить набор символов в строке подключения. Если Вы используете PHP, опробуйте это:

<?php
$link = mysql_connect($host, $usr, $pwd);
mysql_select_db($db);
if (mysql_error()) {
   print "Database ERROR: " . mysql_error();
}
mysql_query("SET NAMES 'utf8'", $link);
?>

В этом случае мы использовали SET NAMES, чтобы изменить character_set_client, character_set_connection и character_set_results.

Правильно использовать более нового расширения mysqli, а не старого mysql. При использовании mysqli предыдущий пример мог бы быть переписан как показано здесь:

<?php
$link = new mysqli($host, $usr, $pwd, $db);
if (mysqli_connect_errno()) {
   printf("Connect failed: %s\n", mysqli_connect_error());
   exit();
}
$link->query("SET NAMES 'utf8'");
?>

Другая проблема, с которой часто сталкиваются в прикладных программах на PHP: что делать с предположениями, сделанными браузером. Иногда добавление или изменение тэга <meta> достаточно, чтобы исправить проблему: например, чтобы обеспечить, чтобы агент пользователя интерпретировал содержание страницы как UTF-8, Вы должны включить <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> в <head> HTML-страницы.

10.11.11: Я обновился до MySQL 5.1. Как я могу возвращаться к поведению, аналогичному MySQL 4.0, относительно наборов символов?

В MySQL 4.0 имелся один глобальный набор символов для клиента и сервера, который назначался администратором. Это изменилось в MySQL 4.1. Когда пользователь соединяется, он посылает серверу имя набора символов, который требуется использовать. Сервер использует это имя, чтобы установить переменные системы character_set_client, character_set_results и character_set_connection. В действительности сервер выполняет операцию SET NAMES, использующую имя набора символов. Эффект этого: Вы не можете управлять набором символов пользователя, запуская mysqld с параметром --character-set-server=utf8. Однако, некоторые заказчики сказали, что предпочитают поведение MySQL 4.0. Чтобы делать возможным сохранить это поведение, разработчики добавили в mysqld переключатель --character-set-client-handshake, который может быть выключен с --skip-character-set-client-handshake. Если Вы запускаете mysqld с --skip-character-set-client-handshake, то, когда пользователь соединяется, это посылает серверу имя набора символов, который требуется использовать. Однако, сервер проигнорирует этот запрос от пользователя.

Например, предположите, что Ваш любимый набор символов сервера latin1 (вряд ли это так в области CJK, но это значение по умолчанию). Предположите далее, что пользователь использует utf8 потому, что операционная система пользователя поддерживает. Теперь запустите сервер с latin1 как заданный по умолчанию набор символов:

mysqld --character-set-server=latin1

Затем запустите пользователя с заданным по умолчанию набором символов utf8:

mysql --default-character-set=utf8

Текущие параметры настройки могут быть выяснены, рассматривая вывод SHOW VARIABLES:

mysql> SHOW VARIABLES LIKE 'char%';
+--------------------------+----------------------------------------+
| Variable_name            | Value                                  |
+--------------------------+----------------------------------------+
| character_set_client     | utf8                                   |
| character_set_connection | utf8                                   |
| character_set_database   | latin1                                 |
| character_set_filesystem | binary                                 |
| character_set_results    | utf8                                   |
| character_set_server     | latin1                                 |
| character_set_system     | utf8                                   |
| character_sets_dir       | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+
8 rows in set (0.01 sec)

Теперь остановите пользователя, а затем и сервер, используя mysqladmin. Затем запустите сервер снова, но на сей раз сообщите, чтобы он не менял набор символов:

mysqld --character-set-server=utf8 --skip-character-set-client-handshake

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

mysql> SHOW VARIABLES LIKE 'char%';
+--------------------------+----------------------------------------+
| Variable_name            | Value                                  |
+--------------------------+----------------------------------------+
| character_set_client     | latin1                                 |
| character_set_connection | latin1                                 |
| character_set_database   | latin1                                 |
| character_set_filesystem | binary                                 |
| character_set_results    | latin1                                 |
| character_set_server     | latin1                                 |
| character_set_system     | utf8                                   |
| character_sets_dir       | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+
8 rows in set (0.01 sec)

Как Вы можете видеть, сравнивая отличия выводов SHOW VARIABLES, сервер игнорирует начальные установки пользователя, если используется опция --skip-character-set-client-handshake.

10.11.12: Почему некоторые LIKE и поиск FULLTEXT с символами CJK срываются?

Имеется очень простая проблема с поисками LIKE на столбцах BINARY и BLOB: мы должны знать конец символа. С многобайтовыми наборами символов, различные символы могли бы иметь различные длины. Например, в utf8, A требует один байт, но уГЪ требует трех байтов, как показано здесь:

+-------------------------+---------------------------+
| OCTET_LENGTH(_utf8 'A') | OCTET_LENGTH(_utf8 'уГЪ') |
+-------------------------+---------------------------+
| 1                       | 3                         |
+-------------------------+---------------------------+
1 row in set (0.00 sec)

Если мы не знаем, где символьные концы, то мы не знаем, где начинаются следующие символы даже в очень простых поисках, типа LIKE '_A%'. Решение состоит в том, чтобы использовать регулярный набор символов CJK или преобразовываться в набор символов CJK перед сравнением.

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

Для поисков FULLTEXT мы должны знать, где слова начинаются и заканчиваются. С западными языками это редко проблема, потому что большинство (если не все) они используют пробел, чтобы идентифицировать конец слова. Однако, это не так с азиатской записью.

10.11.13: Какие наборы символов CJK доступны в MySQL?

Список наборов символов CJK может изменяться в зависимости от Вашей версии MySQL. Например, набор символов eucjpms не обеспечивался до MySQL 5.0.3. Однако, так как имя соответствующего языка появляется в столбце DESCRIPTION для каждого входа в таблице INFORMATION_SCHEMA.CHARACTER_SETS, Вы можете получать текущий список всех не-Unicode наборов символов CJK, используя этот запрос:

mysql> SELECT CHARACTER_SET_NAME, DESCRIPTION FROM
    ->        INFORMATION_SCHEMA.CHARACTER_SETS
    ->        WHERE DESCRIPTION LIKE '%Chinese%' OR
    ->        DESCRIPTION LIKE '%Japanese%' OR DESCRIPTION LIKE '%Korean%'
    ->        ORDER BY CHARACTER_SET_NAME;
+--------------------+---------------------------+
| CHARACTER_SET_NAME | DESCRIPTION               |
+--------------------+---------------------------+
| big5               | Big5 Traditional Chinese  |
| cp932              | SJIS for Windows Japanese |
| eucjpms            | UJIS for Windows Japanese |
| euckr              | EUC-KR Korean             |
| gb2312             | GB2312 Simplified Chinese |
| gbk                | GBK Simplified Chinese    |
| sjis               | Shift-JIS Japanese        |
| ujis               | EUC-JP Japanese           |
+--------------------+---------------------------+
8 rows in set (0.01 sec)

10.11.14: Как я узнаю, является ли символ X доступным во всех наборах символов?

Большинство упрощеннных китайских и японских символов Kana появляются во всех CJK-наборах символов. Эта сохраненная процедура принимает символ UCS-2 Unicode, преобразует это во все другие наборы символов и отображает результаты в шестнадцатеричном формате.

DELIMITER //
CREATE PROCEDURE p_convert(ucs2_char CHAR(1) CHARACTER SET ucs2)
BEGIN
  CREATE TABLE tj (ucs2 CHAR(1) character set ucs2,
                   utf8 CHAR(1) character set utf8,
                   big5 CHAR(1) character set big5,
                   cp932 CHAR(1) character set cp932,
                   eucjpms CHAR(1) character set eucjpms,
                   euckr CHAR(1) character set euckr,
                   gb2312 CHAR(1) character set gb2312,
                   gbk CHAR(1) character set gbk,
                   sjis CHAR(1) character set sjis,
                   ujis CHAR(1) character set ujis);
  INSERT INTO tj (ucs2) VALUES (ucs2_char);
  UPDATE tj SET utf8=ucs2, big5=ucs2, cp932=ucs2, eucjpms=ucs2, euckr=ucs2,
                gb2312=ucs2, gbk=ucs2, sjis=ucs2, ujis=ucs2;

  /* If there's a conversion problem, UPDATE will produce a warning. */
  SELECT hex(ucs2) AS ucs2, hex(utf8) AS utf8, hex(big5) AS big5,
         hex(cp932) AS cp932, hex(eucjpms) AS eucjpms, hex(euckr) AS euckr,
         hex(gb2312) AS gb2312, hex(gbk) AS gbk, hex(sjis) AS sjis,
         hex(ujis) AS ujis FROM tj;
  DROP TABLE tj;
END//

Ввод может быть любым одиночным символом ucs2 или значением отметки кода (шестнадцатеричное представление) для этого символа. Например, из списка Unicode кодирования и имен ucs2 ( http://www.unicode.org/Public/UNIDATA/UnicodeData.txt) мы знаем, что символ Katakana Pe появляется во всех CJK-наборах символов, и что значение отметки кода 0x30da. Если мы используем это значение как параметр для p_convert(), результат показывается здесь:

mysql> CALL p_convert(0x30da)//
+------+--------+------+-------+---------+-----+------+------+------+------+
| ucs2 | utf8   | big5 | cp932 | eucjpms |euckr|gb2312| gbk  | sjis | ujis |
+------+--------+------+-------+---------+-----+------+------+------+------+
| 30DA | E3839A | C772 | 8379  | A5DA    |ABDA |A5DA  | A5DA | 8379 | A5DA |
+------+--------+------+-------+---------+-----+------+------+------+------+
1 row in set (0.04 sec)

Так как ни одно из значений столбца не 3F, то есть символ вопросительного знака (?), мы знаем, что каждое преобразование сработало.

10.11.15: Почему CJK-строки не сортируются правильно в Unicode? (I)

Иногда люди наблюдают, что результат поиска utf8_unicode_ci или ucs2_unicode_ci, либо сортировка ORDER BY не то, что они ожидали. Хотя мы никогда не исключаем возможность, что имеется ошибка, в прошлом было установлено, что много людей не читают правильно стандартную таблицу весов для алгоритма объединения Unicode. MySQL использует таблицу, найденную на http://www.unicode.org/Public/UCA/4.0.0/allkeys-4.0.0.txt. Это не первая таблица, которую Вы найдете, начав с unicode.org, потому что MySQL использует старую таблицу 4.0.0 allkeys , а не более новую 4.1.0. Это потому, что разработчики очень осторожны относительно изменения упорядочения, которое воздействует на индексы, чтобы не вызывать ситуации типа сообщенной в Глюке #16526, иллюстрируемой следующим образом:

mysql< CREATE TABLE tj (s1 CHAR(1) CHARACTER SET utf8 COLLATE
                 utf8_unicode_ci);
Query OK, 0 rows affected (0.05 sec)

mysql> INSERT INTO tj VALUES ('уБМ'),('уБЛ');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM tj WHERE s1 = 'уБЛ';
+-----+
| s1  |
+-----+
| уБМ |
| уБЛ |
+-----+
2 rows in set (0.00 sec)

Символ в первой строке результатов не тот, который мы искали. Почему MySQL находит это? Сначала мы ищем значение отметки кода Unicode, которое является возможным, читая шестнадцатеричный номер для ucs2-версии символов:

mysql> SELECT s1, HEX(CONVERT(s1 USING ucs2)) FROM tj;
+-----+-----------------------------+
| s1  | HEX(CONVERT(s1 USING ucs2)) |
+-----+-----------------------------+
| уБМ | 304C                        |
| уБЛ | 304B                        |
+-----+-----------------------------+
2 rows in set (0.03 sec)

Теперь мы ищем 304B и 304C в таблице 4.0.0 allkeys и находим эти строки:

304B; [.1E57.0020.000E.304B] # HIRAGANA LETTER KA
304C; [.1E57.0020.000E.304B][.0000.0140.0002.3099] # HIRAGANA LETTER GA; QQCM

Официальные имена Unicode (после метки #) сообщают нам японский символ (Hiragana), неофициальную классификацию (символ, цифра или знак препинания) и западный идентификатор (KA или GA, произносимые и непроизносимые компоненты той же самой пары символов). Более важен первичный вес (primary weight , первый шестнадцатеричный номер внутри квадратных скобок) 1E57 на обеих строках. Для сравнений в поиске и сортировке MySQL использует только первичный вес, игнорируя все другие числа. Это означает, что мы сортируем уБМ и уБЛ правильно, согласно Unicode спецификации. Если мы хотим отличить их, мы должны будем использовать non-UCA (Unicode Collation Algorithm) объединение (utf8_unicode_bin или utf8_general_ci), либо сравнивать значения HEX(), либо применять ORDER BY CONVERT(s1 USING sjis). Быть правильным, согласно Unicode, конечно, недостаточно: человек, который представил на рассмотрение ошибку, был прав. Мы планируем добавлять другое объединение для японских символов согласно стандарту JIS X 4061, в котором высказанные/невысказанные пары символов, подобные KA/GA, являются различимыми для целей упорядочения.

10.11.16: Почему CJK-строки не сортируются правильно в Unicode? (дополнение)

Если Вы используете Unicode (ucs2 или utf8) и Вы знаете порядок сортировки Unicode, но MySQL все еще сортирует Вашу таблицу неправильно, то Вы должны сначала проверить набор символов таблицы:

mysql> SHOW CREATE TABLE t\G
******************** 1. row ******************
Table: t
Create Table: CREATE TABLE `t` (`s1` char(1) CHARACTER SET ucs2 DEFAULT NULL)
                     ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Так как набор символов правильный, давайте посмотрим то, какую информацию таблица INFORMATION_SCHEMA.COLUMNS может обеспечивать относительно этого столбца:

mysql> SELECT COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME
    ->        FROM INFORMATION_SCHEMA.COLUMNS
    ->        WHERE COLUMN_NAME = 's1' AND TABLE_NAME = 't';
+-------------+--------------------+-----------------+
| COLUMN_NAME | CHARACTER_SET_NAME | COLLATION_NAME  |
+-------------+--------------------+-----------------+
| s1          | ucs2               | ucs2_general_ci |
+-------------+--------------------+-----------------+
1 row in set (0.01 sec)

Вы можете видеть, что объединение ucs2_general_ci вместо ucs2_unicode_ci. Причина того, почему это так, может быть найдена, используя SHOW CHARSET, как показано здесь:

mysql> SHOW CHARSET LIKE 'ucs2%';
+---------+---------------+-------------------+--------+
| Charset | Description   | Default collation | Maxlen |
+---------+---------------+-------------------+--------+
| ucs2    | UCS-2 Unicode | ucs2_general_ci   | 2      |
+---------+---------------+-------------------+--------+
1 row in set (0.00 sec)

Для ucs2 и utf8 заданное по умолчанию объединение: general. Чтобы определять объединение Unicode, используйте COLLATE ucs2_unicode_ci.

10.11.17: Почему мои дополнительные символы отклонены MySQL?

MySQL не поддерживает дополнительные символы, то есть символы, которые нуждаются больше, чем в 3 байтах для UTF-8. Пакет поддерживает только Basic Multilingual Plane/Plane 0 . Только несколько очень редких символов Han дополнительны; поддержка для них необыкновенна. Это привело к отчетам типа найденного в Глюке #12600, который авторы отклонили как не ошибка. С utf8 мы должны усечь входную строку, когда сталкиваемся с байтами, которые не понимаем. Иначе мы не знали бы, какой длины многобайтовый символ.

Одно возможное решение должно использовать ucs2 вместо utf8, когда символы изменены на вопросительные знаки. Однако, никакое усечение не происходит. Вы можете также изменять тип данных на BLOB или BINARY, которые не выполняют никакую проверку правильности.

10.11.18: Разве это не должен быть CJKV?

Нет. Термин CJKV (Chinese Japanese Korean Vietnamese) обращается к вьетнамским наборам символов, которые содержат Han (изначально китайские) символы. MySQL не имеет никакого плана, чтобы поддерживать старый вьетнамский вариант, использующий символы Han. MySQL поддерживает современный вьетнамский вариант с символами Western.

Глюк #4745 просьба о специализированном вьетнамском объединении, которое может быть добавлено в будущем, если имеется достаточная потребность в этом.

10.11.19: MySQL позволяет символам CJK использоваться в именах баз данных и таблиц?

Эта проблема отфиксирована в MySQL 5.1, автоматически переписывая имена соответствующих каталогов и файлов.

Например, если Вы создаете базу данных цео на сервере, чья операционная система не поддерживает CJK в именах каталогов, MySQL создает каталог @0w@00a5@00ae, который является только причудливым способом кодирования E6A5AE, то есть шестнадцатеричное представление для Unicode-символа цео. Однако, если Вы выполняете инструкцию SHOW DATABASES, Вы можете видеть, что база данных перечислена как цео.

10.11.20: Где я могу находить переводы руководства по MySQL на китайский, корейский и японский языки?

Упрощенная китайская версия руководства для MySQL 5.1.12 может быть найдена на http://dev.mysql.com/doc/#chinese-5.1. Японская для MySQL 4.1 может быть получена с http://dev.mysql.com/doc/#japanese-4.1.

10.11.21: Где я могу получать справку по CJK и связанным проблемам в MySQL?

Следующие ресурсы доступны:

ucs2_unicode_ci, либо сортировка ORDER BY не то, что они ожидали. Хотя мы никогда не исключаем возможность, что имеется ошибка, в прошлом было установлено, что много людей mysqlpro/events.htm 600 0 0 135227 10643272602 7775 Глава 8. Планировщик событий

Глава 8. Планировщик событий

Эта глава описывает планировщик событий MySQL, поддержка которого была добавлена в MySQL 5.1.6.

8.1. Обзор планировщика событий

События MySQL представляют собой задачи, которые выполняются согласно плану. Следовательно, мы иногда обращаемся к ним как к планируемым событиям. Когда Вы создаете событие, Вы создаете именованный объект базы данных, содержащий одну или большее количество инструкций SQL, которые будут выполнены в одном или более регулярных интервалах, начиная и заканчивая в специфическую дату и время. Концептуально, это подобно идее Unix crontab (также известно как cron job) или Windows Task Scheduler.

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

В то время как не имеется никакого средства в стандарте SQL для планирования события, есть прецеденты в других системах баз данных, и Вы можете обратить внимание на некоторые подобия между этими реализациями.

События MySQL имеют следующие главные свойства и реквизиты:

События выполнены специальным потоком планировщика событий. При выполнении поток планировщика события и текущее состояние могут быть замечены пользователями, имеющими привилегию SUPER в выводе SHOW PROCESSLIST, как показано ниже.

Глобальная переменная event_scheduler определяет, включен ли планировщику событий на сервере. При запуске MySQL 5.1.12 это имеет одно из этих 3 значений, которые воздействуют на планируемые события, как описано здесь:

Когда сервер запущен, event_scheduler может переключаться ON и OFF (используя SET). Также возможно использовать 0 для OFF и 1 для ON при установке этой переменной. Таким образом, любая из следующих 4 инструкций может использоваться в клиенте mysql, чтобы включить планировщик событий:

SET GLOBAL event_scheduler = ON;
SET @@global.event_scheduler = ON;
SET GLOBAL event_scheduler = 1;
SET @@global.event_scheduler = 1;

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

SET GLOBAL event_scheduler = OFF;
SET @@global.event_scheduler = OFF;
SET GLOBAL event_scheduler = 0;
SET @@global.event_scheduler = 0;

Хотя ON и OFF имеет числовые эквиваленты, значение, отображаемое для event_scheduler вызовом SELECT или SHOW VARIABLES всегда OFF, ON или DISABLED. Значение DISABLED не имеет никакого числового эквивалента. По этой причине ON и OFF обычно предпочитаются 1 и 0 при установке этой переменной.

Обратите внимание, что делая попытку устанавливать event_scheduler без того, чтобы определять ее как глобальную переменную, вы получите ошибку:

mysql< SET @@event_scheduler = OFF;
ERROR 1229 (HY000): Variable 'event_scheduler' is a
GLOBAL variable and should be set with SET GLOBAL

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

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

Чтобы включить планировщик, перезапустите сервер без параметра --event-scheduler=DISABLED или после удаления (или комментирования) строки, содержащей event_scheduler=DISABLED в файле конфигурации. В качестве альтернативы Вы можете использовать ON (или 1), либо OFF (или 0) вместо значения DISABLED при старте сервера.

Обратите внимание: Вы можете выдавать инструкции манипулирования событиями, когда event_scheduler установлен в DISABLED. Никакие предупреждения или ошибки не будут сгенерированы в таких случаях (если инструкции самостоятельно допустимы). Однако, планируемые события не могут выполняться, пока эта переменная не установлена в ON (или 1). Как только это было выполнено, поток планировщика выполняет все события, чьи планирующие условия удовлетворены.

В MySQL 5.1.11 event_scheduler вела себя следующим образом: эта переменная могла брать одно из значений 0 (или OFF), 1 (или ON) или 2. Установка в 0 отключала планировщик. Установка в 1 запускала планировщик и выполняла планируемые события. В этом состоянии поток планировщика события, казалось, бездействовала когда просматривалась с SHOW PROCESSLIST. Когда event_scheduler была установлена в 2 (что и было значением по умолчанию), планировщик событий был приостановлен: поток планировщика событий выполнялся и мог быть найден в выводе SHOW PROCESSLIST (где в столбце State отображалось Suspended), но не выполнялись никакие планируемые события. Значение event_scheduler могло быть изменено только между 1 (или ON) и 2 во время работы сервера. Установка в OFF или изменение из OFF) требовала рестарта сервера.

До MySQL 5.1.11 event_scheduler мог брать только одно из 2 значений: 0|OFF (по умолчанию) или 1|ON без перезапуска сервера.

MySQL 5.1.6 и позже обеспечивает таблицу EVENTS в базе данных INFORMATION_SCHEMA. Эта таблица может делать запрос к информации относительно планируемых событий, которые были определены на сервере.

8.2. Синтаксис планировщика событий

MySQL 5.1.6 и позже обеспечивает несколько инструкций SQL для работы с планируемыми событиями:

8.2.1. Синтаксис CREATE EVENT

CREATE EVENT [IF NOT EXISTS] event_name
       ON SCHEDULE schedule
       [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE]
       [COMMENT 'comment']
       DO sql_statement;

schedule:
AT timestamp [+ INTERVAL interval]
| EVERY interval [STARTS timestamp]
[ENDS timestamp]

interval:
quantity {YEAR | QUARTER | MONTH | DAY | HOUR |
                       MINUTE | WEEK | SECOND | YEAR_MONTH | DAY_HOUR |
                       DAY_MINUTE | DAY_SECOND | HOUR_MINUTE | HOUR_SECOND |
                       MINUTE_SECOND}

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

Это пример минимальной инструкции

CREATE EVENT myevent
       ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
       DO UPDATE myschema.mytable SET mycol = mycol + 1;

Предыдущая инструкция создает событие myevent. Это событие выполняется один раз в час после создания, выполняя инструкцию SQL, которая увеличивает значение столбца mycol таблицы myschema.mytable на 1.

Имя event_name должно быть допустимым идентификатором MySQL с максимальной длиной в 64 символа. Это может быть разграничено, используя обратные импульсы сигнала времени, и может быть квалифицировано с именем схемы базы данных. Событие связано с пользователем MySQL (definer) и схемой, так что имя должно быть уникальным среди имен событий внутри этой схемы. Вообще, правила, управляющие именами событий, такие же, как для имен сохраненных подпрограмм, поскольку события по сути и являются такими подпрограммами, только особыми.

Если никакая схема не обозначена как часть event_name, то принята заданная по умолчанию схема. Definer всегда текущий пользователь MySQL.

До MySQL 5.1.12 было возможно для двух различных пользователей создать различные события, имеющие то же самое имя в той же самой схеме базы данных.

Обратите внимание: MySQL использует сравнения без учета регистра при прверке уникальности имен события. Это означает, что, например, Вы не можете иметь два события events named myevent и MyEvent в той же самой схеме базы данных.

Функция IF NOT EXISTS с инструкцией CREATE EVENT работает полностью аналогично варианту с CREATE TABLE: если событие event_name уже существует в той же самой схеме, никаких действий не предпринимается, и никакой ошибки не будет. Однако, предупреждение будет сгенерировано.

Предложение ON SCHEDULE определяет, когда, как часто и как долго sql_statement определено для повторения события. Это предложение берет одну из двух форм:

Предложение ON SCHEDULE может использовать выражения, включающие встроенные функции MySQL и переменные пользователя, чтобы получить любое значение timestamp или interval. Вы не можете использовать сохраненные подпрограммы или определяемые пользователем функции в таких выражениях, и при этом Вы не можете использовать любые ссылки на таблицы, однако, Вы можете SELECT FROM DUAL. Это истинно для инструкций CREATE EVENT и ALTER EVENT. Начиная с MySQL 5.1.13, ссылки на сохраненные подпрограммы, определяемые пользователем функции и таблицы в таких случаях специально отвергнуты и вызывают сбой с ошибкой (Глюк #22830).

Обычно, как только событие истекло, оно немедленно уничтожается. Вы можете отменять это поведение, определяя ON COMPLETION PRESERVE. Использование ON COMPLETION NOT PRESERVE просто делает заданное по умолчанию поведение явным.

Вы можете создавать событие и сохранить его неактивным для дальнейшего неспешного потребления, используя ключевое слово DISABLE. В качестве альтернативы Вы можете использовать ENABLE, чтобы сделать явным заданное по умолчанию состояние, которое является активным. Это наиболее полезно вместе с ALTER EVENT.

Вы можете обеспечивать комментарий для события, используя предложение COMMENT. Здесь comment может быть любой строкой до 64 символов, которые Вы желаете использовать для описания события. Текст комментария, являющийся строковым литералом, должен быть окружен кавычками.

Предложение DO определяет действие, которое несет событие, и состоит из инструкции SQL. Почти любая допустимая инструкция MySQL, которая может использоваться в сохраненной подпрограмме, может также использоваться как инструкция действия для планируемого события. Например, следующее событие e_hourly удаляет все строки из таблицы sessions раз в час, если только эта таблица часть схемы site_activity:

CREATE EVENT e_hourly ON SCHEDULE
       EVERY 1 HOUR COMMENT 'Clears out sessions table each hour.'
       DO DELETE FROM site_activity.sessions;

Инструкция CREATE EVENT, которая содержит инструкцию ALTER EVENT в предложении DO, появляется, однако, когда сервер пытается выполнить возникающее в результате планируемое событие, получается сбой выполнения с ошибкой.

Обратите внимание: инструкции SHOW и SELECT, которые просто возвращают набор результатов, не имеют никакого эффекта, когда используются в событии, вывод из них не будет послан MySQL Monitor. Однако, Вы можете использовать инструкции типа SELECT INTO и INSERT ... SELECT, которые сохраняют результат.

Любая ссылка в предложении DO к таблице в другой схеме базы данных должна быть квалифицирована с именем схемы, в которой таблица находится. В MySQL 5.1.6 все таблицы, вызванные в предложениях DO событий должны были включать ссылку на базу данных.

Как и в случае с сохраненными подпрограммами, Вы можете использовать много инструкций в предложении DO заключением их в слова BEGIN и END, как показано здесь:

DELIMITER |
CREATE EVENT e_daily ON SCHEDULE
       EVERY 1 DAY
       COMMENT 'Saves total number of sessions then clears the table each day.'
       DO BEGIN
   INSERT INTO site_activity.totals (when, total)
   SELECT CURRENT_TIMESTAMP, COUNT(*)
   FROM site_activity.sessions;
   DELETE FROM site_activity.sessions;
END |
DELIMITER ;

Обратите внимание на использование инструкции DELIMITER, чтобы изменить операторный разделитель, как с сохраненными подпрограммами.

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

DELIMITER |
CREATE EVENT e ON SCHEDULE
       EVERY 5 SECOND DO BEGIN
   DECLARE v INTEGER;
   DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
   SET v = 0;
   WHILE v < 5 DO
     INSERT INTO t1 VALUES (0);
     UPDATE t2 SET s1 = s1 + 1;
     SET v = v + 1;
   END WHILE;
END |
DELIMITER ;

Не имеется никакого способа передать параметры непосредственно событию, однако, возможно вызвать сохраненную подпрограмму с параметрами:

CREATE EVENT e_call_myproc ON SCHEDULE
       AT CURRENT_TIMESTAMP + 1 DAY
       DO CALL myproc(5, 27);

Кроме того, если definer события имеет привилегию SUPER, то событие может читать и записывать глобальные переменные. Так как предоставление этой привилегии влечет за собой потенциал для неправильного обращения, критическая осторожность должна быть проявлена.

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

8.2.2. Синтаксис ALTER EVENT

ALTER EVENT event_name
      [ON SCHEDULE schedule]
      [RENAME TO new_event_name]
      [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE]
      [COMMENT 'comment']
      [DO sql_statement]

Инструкция ALTER EVENT используется, чтобы изменить одну или большее количество характеристик существующего события. Синтаксис для каждого из предложений ON SCHEDULE, ON COMPLETION, COMMENT, ENABLE / DISABLE и DO точно такой же, как когда они используются с CREATE EVENT.

Начиная с MySQL 5.1.12, любой пользователь может изменять событие, определенное в базе данных, для которой этот пользователь имеет привилегию EVENT. Когда пользователь выполняет успешную инструкцию ALTER EVENT он становится definer для произведенного события.

В MySQL 5.1.11 и ранее событие могло быть изменено только definer или пользователем, имеющим привилегию SUPER. ALTER EVENT работает только с существующим событием:

mysql> ALTER EVENT no_such_event
     >       ON SCHEDULE
     >       EVERY '2:3' DAY_HOUR;
ERROR 1517 (HY000): Unknown event
'no_such_event'

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

CREATE EVENT myevent ON SCHEDULE
       EVERY 6 HOUR COMMENT 'A sample comment.'
       DO UPDATE myschema.mytable SET mycol = mycol + 1;

Следующая инструкция изменяет план для myevent с одного раза каждые шесть часов (запуск немедленно) на один раз каждые двенадцать часов, запуская четыре часа со времени выполнения инструкции:

ALTER EVENT myevent ON SCHEDULE
      EVERY 12 HOUR STARTS
      CURRENT_TIMESTAMP + 4 HOUR;

Чтобы отключить myevent используйте эту инструкцию ALTER EVENT:

ALTER EVENT myevent DISABLE;

Предложение ON SCHEDULE может использовать выражения, включающие встроенные функции MySQL и переменные пользователя, чтобы получить любой timestamp или interval. Вы не можете использовать сохраненные подпрограммы или определяемые пользователем функции в таких выражениях, и при этом Вы не можете использовать любые ссылки на таблицы, однако, Вы можете использовать SELECT FROM DUAL.

Инструкция ALTER EVENT, которая содержит другую инструкцию ALTER EVENT в предложении DO, допустима. Однако, когда сервер пытается выполнять возникающее в результате планируемое событие, произойдет сбой с ошибкой.

Возможно изменить много характеристик события в одиночной инструкции. Этот пример изменяет инструкцию SQL, выполненную myevent, а также план для события:

ALTER TABLE myevent ON SCHEDULE
      AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
      DO TRUNCATE TABLE myschema.mytable;

Чтобы переименовывать событие, используйте предложение RENAME TO инструкции ALTER EVENT, как показано здесь:

ALTER EVENT myevent RENAME TO yourevent;

Предыдущая инструкция переименовывает событие myevent в yourevent. Примечание : не имеется никакой инструкции RENAME EVENT.

Вы можете также переместить событие в другую схему, используя ALTER EVENT ... RENAME TO ... и запись в формате schema_name.table_name, как показано здесь:

ALTER EVENT oldschema.myevent RENAME TO newschema.myevent;

Чтобы выполнять предыдущую инструкцию, пользователь, выполняющий это, должен иметь привилегию EVENT на схемах oldschema и newschema базы данных.

Необходимо включить только те параметры в инструкцию ALTER EVENT, которые соответствуют характеристикам, которые Вы фактически желаете изменить, параметры, которые опущены, сохраняют их существующие значения. Это включает любые значения по умолчанию для CREATE EVENT, например, ENABLE.

8.2.3. Синтаксис DROP EVENT

DROP EVENT [IF EXISTS] event_name

Эта инструкция удаляет событие event_name. Событие немедленно прекращает активность и будет удалено полностью с сервера.

Если событие не существует, произойдет ошибка ERROR 1517 (HY000): Unknown event 'event_name'. Вы можете поменять это и заставить инструкцию провалиться тихо, используя опцию IF EXISTS.

Начиная с MySQL 5.1.12, событие может быть удалено любым пользователем, имеющим привилегию EVENT на схеме базы данных, событие в которой должно быть удалено. В MySQL 5.1.11 и ранее событие могло быть удалено только definer или пользователем, имеющим привилегию SUPER.

8.3. Метаданные события

Информация относительно событий может быть получена следующим образом:

8.4. Состояние планировщика событий

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

8.5. Планировщик событий и привилегии MySQL

Чтобы включить или отключить выполнение планируемых событий, необходимо установить значение глобальной переменной event_scheduler. Это требует привилегии SUPER.

MySQL 5.1.6 представляет привилегию EVENT, управляя созданием, модификацией и стиранием событий. Эта привилегия может быть подарена, используя GRANT. Например, эта инструкция GRANT предоставляет привилегию EVENT для схемы myschema на пользователя jon@ghidora:

GRANT EVENT ON myschema.* TO jon@ghidora;

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

GRANT EVENT ON *.* TO jon@ghidora;

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

mysql> GRANT EVENT ON myschema.mytable TO jon@ghidora;
ERROR 1144 (42000): Illegal GRANT/REVOKE command;
please consult the manual to see which privileges can be used

Важно понять, что событие выполнено с привилегиями definer, и что оно не может выполнять любые действия, для которых definer не имеет необходимых привилегий. Например, предположим, что jon@ghidora имеет привилегию EVENT для myschema. Предположим также, что этот пользователь имеет привилегию SELECT для myschema, но никаких других привилегий для этой схемы он не имеет. Возможно для jon@ghidora создать новое событие типа этого:

CREATE EVENT e_store_ts ON SCHEDULE
       EVERY 10 SECOND DO
       INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP());

Пользователь ждет в течение минуты или более, а затем выполняет запрос SELECT * FROM mytable;, ожидая, что увидит несколько новых строк в таблице. Вместо этого он находит, что таблица пуста: так как он не имеет привилегии INSERT для рассматриваемой таблицы, событие не имеет никакого эффекта.

Если Вы осматриваете файл регистрации ошибок MySQL (hostname.err), Вы можете видеть, что событие-то выполняется, но действие это вызывает сбой, как обозначено RetCode=0:

060209 22:39:44 [Note] EVEX EXECUTING event newdb.e [EXPR:10]
060209 22:39:44 [Note] EVEX EXECUTED event newdb.e[EXPR:10]. RetCode=0
060209 22:39:54 [Note] EVEX EXECUTING event newdb.e [EXPR:10]
060209 22:39:54 [Note] EVEX EXECUTED event newdb.e[EXPR:10]. RetCode=0
060209 22:40:04 [Note] EVEX EXECUTING event newdb.e [EXPR:10]
060209 22:40:04 [Note] EVEX EXECUTED event newdb.e[EXPR:10]. RetCode=0

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

mysql> INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP());
ERROR 1142 (42000): INSERT command denied to user
'jon'@'ghidora' for table 'mytable'

Проверка таблицы INFORMATION_SCHEMA.EVENTS показывает, что e_store_ts существует и включен, но столбец LAST_EXECUTED записан NULL:

mysql> SELECT * FROM INFORMATION_SCHEMA.EVENTS
     >          WHERE EVENT_NAME='e_store_ts'
     >          AND EVENT_SCHEMA='myschema'\G
*************************** 1. row ***************************
EVENT_CATALOG: NULL
EVENT_SCHEMA: myschema
EVENT_NAME: e_store_ts
DEFINER: jon@ghidora
EVENT_BODY: SQL
EVENT_DEFINITION: INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP())
EVENT_TYPE: RECURRING
EXECUTE_AT: NULL
INTERVAL_VALUE: 5
INTERVAL_FIELD: INTERVAL_SECOND
SQL_MODE: NULL
STARTS: 0000-00-00 00:00:00
ENDS: 0000-00-00 00:00:00
STATUS: ENABLED
ON_COMPLETION: NOT PRESERVE
CREATED: 2006-02-09 22:36:06
LAST_ALTERED: 2006-02-09 22:36:06
LAST_EXECUTED: NULL
EVENT_COMMENT:
1 row in set (0.00 sec)

(Обратите внимание: до MySQL 5.1.12 не было столбца EVENT_DEFINITION, по причине чего EVENT_BODY содержал инструкцию SQL или инструкции, которые будут выполнены.

Чтобы отменить привилегию EVENT, используйте инструкцию REVOKE. В этом примере привилегия EVENT на схеме myschema удалена из логина пользователя jon@ghidora:

REVOKE EVENT ON myschema.* FROM jon@ghidora;

Важно: отмена привилегии EVENT пользователя не удаляет и не отключает никакие события, которые, возможно, были им созданы!

Например, предположим, что пользователю jon@ghidora предоставили привилегии EVENT и INSERT на схеме myschema. Этот пользователь затем создает следующее событие:

CREATE EVENT e_insert ON SCHEDULE
       EVERY 7 SECOND DO
       INSERT INTO myschema.mytable;

После того, как это событие было создано, root отменяет привилегию EVENT для jon@ghidora. Однако, e_insert продолжает выполняться, вставляя новую строку в mytable каждые семь секунд.

Определения событий сохранены в таблице mysql.event, которая была добавлена в MySQL 5.1.6. Чтобы удвлить событие, созданное другим пользователем, MySQL-пользователь root (или другой пользователь с необходимыми привилегиями) может удалять строки из этой таблицы. Например, чтобы удалить событие e_insert, показанное выше, root может использовать следующую инструкцию:

DELETE FROM mysql.event
       WHERE db = 'myschema' AND
             definer = 'jon@ghidora' AND name = 'e_insert';

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

Обратите внимание: пространство имен для планируемых событий изменено в MySQL 5.1.12. До этого MySQL различные пользователи могли создавать различные события, имеющие то же самое имя в той же самой базе данных, в MySQL 5.1.12 и позже это не так. При обновлении на MySQL 5.1.12 или позже с MySQL 5.1.11 или ранее до выполнения обновления чрезвычайно важно удостовериться, что никакие события в той же самой базе данных не используют совместно то же самое имя.

Привилегии EVENT пользователей сохранены в столбцах Event_priv таблиц mysql.user и mysql.db. В обоих случаях этот столбец хранит одно из значений 'Y' или 'N' (по умолчанию 'N'). mysql.user.Event_priv установлен в 'Y' для данного пользователя только, если этот пользователь имеет глобальную привилегию EVENT (то есть, если привилегия была подарена, используя GRANT EVENT ON *.*). Для привилегии EVENT уровня схемы GRANT создает строку в mysql.db и устанавливает столбец Db той строки к имени схемы, столбец User к имени пользователя и Event_priv столбца в 'Y'. Никогда не должно быть никакой потребности управлять этими таблицами непосредственно, так как GRANT EVENT и инструкция REVOKE EVENT выполняют требуемые операции на них.

MySQL 5.1.6 представляет пять переменных состояния, обеспечивающих подсчет связанных с событием операций (но не инструкций, выполненных событиями). Они:

Вы можете просматривать текущие значения для все них в одно время, выполняя инструкцию SHOW STATUS LIKE '%event%';.

8.6. Ограничения планировщика событий

Этот раздел вносит в список ограничения планирования событий в MySQL.

В MySQL любая таблица, вызванная в инструкции действия события должна быть полностью квалифицирована именем схемы, в которой это происходит (то есть, как schema_name.table_name ).

Событие не может быть создано, изменено или удалено триггером, сохраненной подпрограммой или другим событием. Событие также не может создавать, изменять или удалять триггеры или сохраненные подпрограммы (Глюк #16409 и Глюк #18896).

Синхронизации события, использующие интервалы YEAR, QUARTER, MONTH и YEAR_MONTH отсчитываются в месяцах, любой другой интервал отсчитывается в секундах. Не имеется никакого способа заставить планируемые события, происходящие в тот же самый момент, выполниться в заданном порядке. Кроме того, из-за округления, характера прикладных программ и того факта, что ненулевой отрезок времени требуется, чтобы создать событие и сообщить о выполнении, события могут быть отсрочены на целых 1 или 2 секунды. Однако, время, показанное в столбце LAST_EXECUTED таблицы INFORMATION_SCHEMA.EVENTS или столбце last_executed таблицы mysql.event является всегда точным до секунды относительно момента, когда событие было фактически выполнено (Глюк #16522).

Выполнение инструкций события не воздействует на серверные счетчики, вроде Com_select и Com_insert, которые отображаются командой SHOW STATUS.

До MySQL 5.1.12 Вы не могли просматривать события другого пользователя в таблице INFORMATION_SCHEMA.EVENTS. Другими словами, любой запрос, сделанный к этой таблицы обрабатывался, как если бы содержал DEFINER = CURRENT_USER() в предложении WHERE.

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

События не поддерживают времена позже, чем конец Unix Epoch, это приблизительно конец 2037 года. До MySQL 5.1.8 обработка в планируемых событиях дат позже чем, эта вызывала сбой, теперь такие даты специально отвергнуты планировщиком событий (Глюк #16396).

В MySQL 5.1.6 INFORMATION_SCHEMA.EVENTS показывает NULL в столбце SQL_MODE. Начиная с 5.1.7, SQL_MODE отображает то, что было в действительности, когда событие было создано.

В MySQL 5.1.6 единственным способом удалять или менять событие, созданное пользователем, который не был definer этого события, было манипулирование таблицей системы mysql.event MySQL-пользователем root или другим пользователем с привилегиями на этой таблице. В MySQL 5.1.7 и выше DROP USER удаляет все события, для которых этот пользователь был definer, также DROP SCHEMA удаляет все события, связанные с удаляемой схемой.

Как с сохраненными подпрограммами, события не перенесены к новой схеме инструкцией RENAME SCHEMA (или RENAME DATABASE).

Начиная с MySQL 5.1.8, имена событий обработаны в нечувствительном к регистру режиме. Например, это означает, что Вы не можете иметь два события в той же самой базе данных с именами anEvent и AnEvent (а до MySQL 5.1.12 еще и с тем же самым definer). Важно: если Вы имеете события, созданные в MySQL 5.1.7 или ранее, которые назначены к той же самой базе данных, имеют тот же самый definer, и чьи имена отличаются только регистром символов, то Вы бы переименовали эти события, чтобы избежать проблем с обработкой учета регистра перед обновлением до MySQL 5.1.8 или позже.

Ссылки на сохраненные подпрограммы, определяемые пользователем функции и таблицы в предложениях ON SCHEDULE инструкций CREATE EVENT и ALTER EVENT не обеспечиваются (Глюк #22830).

to user 'jon'@'ghidora' for table 'mytable'

Проверка таблицы INFORMATION_SCHEMA.EVENTS показывает, что e_store_ts существует и включен, но столбец LAST_EXECUTED записан NULL:

mysql> SELECT * FROM INFORMATION_SCHEMA.EVENTS
     >          WHERE EVENT_NAME='e_store_mysqlpro/math.htm   600      0      0       61736 10643272636   7414 

   
   
   
   Глава 1. Точная математика




Глава 1. Точная математика

MySQL 5.1 обеспечивает поддержку для точной математики: числовая обработка значения, которая приводит к чрезвычайно точным результатам, и высокой степени контроль над недопустимыми значениями. Точность основана на этих двух свойствах:

Эти свойства имеют несколько импликаций для числовых операций:

Важный результат этих свойств: MySQL 5.1 обеспечивает высокую степень согласия со стандартом SQL.

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

1.1. Типы числовых значений

Контекст математической точности для операций с точным значением включает типы данных с точным значением (DECIMAL и целочисленные типы) и числовые литералы с точным значением. Типы данных с приблизительным значением и числовые литералы все еще обработаны как числа с плавающей запятой.

Числовые литералы с точным значением имеют целочисленную, дробную части или обе. Они могут быть со знаком или без него. Примеры: 1, .2, 3.4, -5, -6.78, +9.10.

Числовые литералы с приблизительным значением представляются в экспоненциальном формате с мантиссой и экспонентой. Любая из частей или обе могут иметь знак. Примеры: 1.2E3, 1.2E-3, -1.2E3, -1.2E-3.

Два числа, которые выглядят одинаково, могут не быть оба точными или приблизительными. Например, 2.34 представляет собой число с точным значением (с фиксированной запятой), в то время как 2.34E0 задает число с приблизительным значением (с плавающей запятой).

Тип данных DECIMAL является типом с фиксированной запятой, и вычисления точны. В MySQL тип DECIMAL имеет несколько синонимов: NUMERIC, DEC, FIXED. Целочисленные типы также типы с точным значением.

Типы данных FLOAT и DOUBLE являются типами с плавающей запятой, и вычисления приблизительны. В MySQL типы, которые являются синонимичными с FLOAT или DOUBLE, это DOUBLE PRECISION и REAL.

1.2. Изменения типа данных DECIMAL

Этот раздел обсуждает характеристики типа данных DECIMAL (и синонимов) в MySQL 5.1, со специфическим отношением к следующим темам

Возможные несовместимости с прикладными программами, которые написаны для старых версий MySQL, отмечены в этом разделе.

Синтаксис объявления для столбца DECIMAL: DECIMAL(M,D). Диапазоны значений для параметров в MySQL 5.1 следующие:

Максимальное значение 65 для M означает, что вычисления на значениях DECIMAL точны до 65 цифр. Это ограничение точности в 65 цифр также применяется к числовым литералам с точным значением, так что оно задает максимальный диапазон таких литералов. В старых версиях MySQL десятичные значения могли иметь до 254 цифр. Однако, вычисления были выполнены, используя числа с плавающей запятой и таким образом были приблизительны, не точны.

Значения для столбцов DECIMAL в MySQL 5.1 сохранены, используя двоичный формат, который упаковывает девять десятичных цифр в четыре байта. Требования к памяти для целочисленных и дробных частей каждого значения определены отдельно. Каждые девять цифр требуют четырех байт, и любые цифры сверх этого требуют некоторой доли четырех байтов. Например, DECIMAL(18,9) имеет девять цифр с обеих сторон десятичной точки, так что целочисленная и дробная части требуют четырех байтов каждая. Столбец DECIMAL(20,10) имеет по десять цифр с обеих сторон десятичной точки. Каждая часть требует четырех байтов для девяти из цифр и одного байта для остающейся цифры.

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

Остающиеся цифры Число байтов
00
11
21
32
42
53
63
74
84
94

В отличие от старых версий MySQL (до 5.0.3), столбцы DECIMAL в MySQL 5.1 не сохраняют символ + или цифры 0 в начале значения. Если Вы вставляете +0003.1 в столбец DECIMAL(5,1), это сохранено как 3.1. Прикладные программы, которые полагаются на старое поведение, должны измениться, чтобы обработать это изменение.

Столбцы DECIMAL в MySQL 5.1 не позволяют значения больше, чем диапазон, подразумеваемый по определению столбца. Например, столбец DECIMAL(3,0) поддерживает диапазон от -999 до 999. А столбец DECIMAL(M,D) позволяет M цифр налево от десятичной точки. Это не совместимо с прикладными программами, полагающимися на старые версии MySQL, которые разрешали сохранять дополнительную цифру вместо знака +.

SQL-стандарт требует, чтобы точность NUMERIC(M,D) была точно M цифр. Для DECIMAL(M,D) стандарт требует точности по крайней мере M цифр, но позволяет больше. В MySQL DECIMAL(M,D) и NUMERIC(M,D) то же самое, и оба типа имеют точность ровно M цифр.

1.3. Обработка выражений

Числа с точным значением используются как даны всякий раз, когда возможно. Например, числа в сравнениях используются точно как даны, без изменения в значении. В строгом SQL-режиме для INSERT в столбец с точным типом данных (DECIMAL или целое число), значение вставлено с точным значением, если оно внутри диапазона столбца. Когда значение получено, оно должно быть таким же как то, что было вставлено. Без строгого режима допустимо усечение для INSERT.

Обработка числового выражения зависит от значений, которое выражение содержит:

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

На вставки в числовые столбцы воздействует SQL-режим, который управляется переменной системы sql_mode. Следующее обсуждение упоминает строгий режим (выбранный значениями режима STRICT_ALL_TABLES или STRICT_TRANS_TABLES) и ERROR_FOR_DIVISION_BY_ZERO. Чтобы включить все ограничения, Вы можете просто использовать режим TRADITIONAL, который включает строгие значения режима и ERROR_FOR_DIVISION_BY_ZERO:

mysql> SET sql_mode='TRADITIONAL';

Если число вставлено в столбец точного типа (DECIMAL или целое число), оно вставлено с точным значением, если находится внутри диапазона столбца.

Если значение имеет слишком много цифр в дробной части, происходит округление, и будет сгенерировано предупреждение. Округление выполнено как описано в разделе " 1.4. Поведение округления".

Если значение имеет слишком много цифр в целочисленной части, оно слишком большое и обработано следующим образом:

По умолчанию, деление на нуль производит результат NULL и никакого предупреждения. С включенным режимом SQL ERROR_FOR_DIVISION_BY_ZERO MySQL обрабатывает деление на нуль по-другому:

Другими словами, вставки и модификации, включающие выражения, которые выполняют деление на нуль, могут обрабатываться как ошибки, но это требует ERROR_FOR_DIVISION_BY_ZERO в дополнение к строгому режиму.

Предположим, что мы имеем эту инструкцию:

INSERT INTO t SET i = 1/0;

Это что случается для комбинации строгого режима и ERROR_FOR_DIVISION_BY_ZERO:

Значение sql_mode Результат
'' (значение по умолчанию)Никаких предупреждений и ошибок: i установлен в NULL.
strictНикаких предупреждений и ошибок: i установлен в NULL.
ERROR_FOR_DIVISION_BY_ZEROНикаких ошибок, но есть предупреждение: i установлен в NULL.
strict,ERROR_FOR_DIVISION_BY_ZEROОшибка: никакая строка не вставлена.

Для вставок строк в числовые столбцы, преобразование из строки в число обработано следующим образом, если строка имеет нечисловое содержание:

1.4. Поведение округления

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

Функция ROUND() работает по-разному в зависимости от того, является ли параметр точным или приблизительным числом:

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

mysql> SELECT ROUND(2.5), ROUND(25E-1);
+------------+--------------+
| ROUND(2.5) | ROUND(25E-1) |
+------------+--------------+
| 3          | 2            |
+------------+--------------+

Для вставок в DECIMAL или целочисленный столбец, если адресат представляет собой точный тип данных, используется метод "округления половины" независимо от того, является ли значение, которое будет вставлено, точным или приблизительным:

mysql> CREATE TABLE t (d DECIMAL(10,0));
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO t VALUES(2.5),(2.5E0);
Query OK, 2 rows affected, 2 warnings (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 2

mysql> SELECT d FROM t;
+------+
| d    |
+------+
| 3    |
| 3    |
+------+

1.5. Примеры математической точности

Этот раздел обеспечивает некоторые примеры, которые показывают запросы с математической точностью в MySQL 5.1.

Пример 1. Числа используются с их точным значением, как даны, когда возможно:

mysql> SELECT .1 + .2 = .3;
+--------------+
| .1 + .2 = .3 |
+--------------+
| 1            |
+--------------+

Для значений с плавающей запятой, результаты неточны:

mysql> SELECT .1E0 + .2E0 = .3E0;
+--------------------+
| .1E0 + .2E0 = .3E0 |
+--------------------+
| 0                  |
+--------------------+

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

CREATE PROCEDURE p ()
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE d DECIMAL(10,4) DEFAULT 0;
  DECLARE f FLOAT DEFAULT 0;
  WHILE i < 10000 DO
    SET d = d + .0001;
    SET f = f + .0001E0;
    SET i = i + 1;
  END WHILE;
  SELECT d, f;
END;

Сумма для d и f логически должна быть 1, но это истинно только для десятичного вычисления. Вычисление с плавающей запятой представляет маленькие ошибки:

+--------+------------------+
|      d |                f |
+--------+------------------+
| 1.0000 | 0.99999999999991 |
+--------+------------------+

Пример 2. Умножение выполняется с масштабом, требуемым стандартом SQL. То есть, для двух чисел X1 и X2, которые имеют масштаб S1 и S2, масштаб результата: S1+S2:

mysql> SELECT .01 * .01;
+-----------+
| .01 * .01 |
+-----------+
|    0.0001 |
+-----------+

Пример 3. Поведение округления четко:

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

Округление для столбцов с точным значением использует округление половины, как показано здесь:

mysql> SELECT ROUND(2.5), ROUND(-2.5);
+------------+-------------+
| ROUND(2.5) | ROUND(-2.5) |
+------------+-------------+
|          3 |          -3 |
+------------+-------------+

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

mysql> SELECT ROUND(2.5E0), ROUND(-2.5E0);
+--------------+---------------+
| ROUND(2.5E0) | ROUND(-2.5E0) |
+--------------+---------------+
|            2 |            -2 |
+--------------+---------------+

Пример 4. В строгом режиме вставка значения, которое является слишком большим, приводит к переполнению и ошибке, а не к усечению до допустимого значения. Когда MySQL не выполняется в строгом режиме, происходит усечение к допустимому значению:

mysql> SET sql_mode='';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t SET i = 128;
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> SELECT i FROM t;
+------+
|    i |
+------+
|  127 |
+------+
1 row in set (0.00 sec)

Однако, условие переполнения происходит, если включен строгий режим:

mysql> SET sql_mode='STRICT_ALL_TABLES';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t SET i = 128;
ERROR 1264 (22003): Out of range value adjusted for column 'i' at row 1
mysql> SELECT i FROM t;
Empty set (0.00 sec)

Пример 5: В строгом режиме и с настройкой ERROR_FOR_DIVISION_BY_ZERO деление на нуль вызывает ошибку, а не результат NULL.

В нестрогом режиме деление на нуль имеет результат NULL:

mysql> SET sql_mode='';
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO t SET i = 1 / 0;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT i FROM t;
+------+
|    i |
+------+
| NULL |
+------+
1 row in set (0.03 sec)

Однако, деление на нуль выдает ошибку, если соответствующие SQL-режимы активны:

mysql> SET sql_mode='STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE t (i TINYINT);
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t SET i = 1 / 0;
ERROR 1365 (22012): Division by 0
mysql> SELECT i FROM t;
Empty set (0.01 sec)

Пример 6. До MySQL 5.0.3 литералы с точным значением и с приблизительным значением преобразованы в значения с плавающей запятой двойной точности:

mysql> SELECT VERSION();
+------------+
|  VERSION() |
+------------+
| 4.1.18-log |
+------------+
1 row in set (0.01 sec)

mysql> CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b;
Query OK, 1 row affected (0.07 sec)
Records: 1 Duplicates: 0 Warnings: 0

mysql> DESCRIBE t;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
|     a | double(3,1) |      |     |     0.0 |       |
|     b | double      |      |     |       0 |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.04 sec)

Начиная с MySQL 5.0.3, литерал с приблизительным значением все еще преобразован в значение с плавающей запятой, но литерал с точным значением обработан как DECIMAL:

mysql> SELECT VERSION();
+-----------------+
|       VERSION() |
+-----------------+
| 5.1.6-alpha-log |
+-----------------+
1 row in set (0.11 sec)

mysql> CREATE TABLE t SELECT 2.5 AS a, 25E-1 AS b;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0

mysql> DESCRIBE t;
+-------+-----------------------+------+-----+---------+-------+
| Field |                  Type | Null | Key | Default | Extra |
+-------+-----------------------+------+-----+---------+-------+
|     a | decimal(2,1) unsigned |   NO |     |     0.0 |       |
|     b |                double |   NO |     |       0 |       |
+-------+-----------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

Пример 7. Если параметр функции точный числовой тип, результат также точный числовой тип, с масштабом по крайней мере, как у параметра. Рассмотрите эти инструкции:

mysql> CREATE TABLE t (i INT, d DECIMAL, f FLOAT);
mysql> INSERT INTO t VALUES(1,1,1);
mysql> CREATE TABLE y SELECT AVG(i), AVG(d), AVG(f) FROM t;

Результаты до MySQL 5.0.3:

mysql> DESCRIBE y;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| AVG(i) | double(17,4) | YES  |     |    NULL |       |
| AVG(d) | double(17,4) | YES  |     |    NULL |       |
| AVG(f) | double       | YES  |     |    NULL |       |
+--------+--------------+------+-----+---------+-------+

Результат двойной точности, независимо от типа параметра. А вот результаты в MySQL 5.0.3 и выше:

mysql> DESCRIBE y;
+--------+---------------+------+-----+---------+-------+
| Field  | Type          | Null | Key | Default | Extra |
+--------+---------------+------+-----+---------+-------+
| AVG(i) | decimal(14,4) | YES  |     |    NULL |       |
| AVG(d) | decimal(14,4) | YES  |     |    NULL |       |
| AVG(f) | double        | YES  |     |    NULL |       |
+--------+---------------+------+-----+---------+-------+

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

5E-1); +---------mysqlpro/mysqlpro.htm 600 0 0 2243 10643272650 10311 MySQL: руководство профессионала

MySQL: руководство профессионала

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

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

Данный материал подготовлен Паутовым Алексеем в рамках некоммерческого проекта RussianLDP:MySQL. При любом использовании ссылка на автора и проект обязательна! , чтобы добавить маленькое число к сумме много раз. Рассмотрите следующую сохраненную процедуру, которая добавляет .0001 к переменной 1000 раз:

CREATE PROCEDURE p ()
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE d DECIMAL(10,4) DEFAULT 0;
  DECLARE f FLOAT DEFAULT 0;
  WHILE i < 10000 DO
    SET d = d + .0001;
 mysqlpro/oglavpro.htm   600      0      0      100510 10643273434  10311 

   
   
   
   MySQL: руководство профессионала. Оглавление



MySQL: руководство профессионала

. Таблица INFORMATION_SCHEMA CHARACTER_SETS
  • 9.10. Таблица INFORMATION_SCHEMA COLLATIONS
  • Глава 3. Выделение разделов (Partitioning)

    Глава 3. Выделение разделов (Partitioning)

    Из-за проблем с формированием двоичный дистрибутив MySQL 5.1.12 не содержат NDB Cluster или Partitioning. Пожалуйста, обновитесь до 5.1.14. Если Вы формируете пакет из исходника, Вы можете выполнять выбор конфигурации configure с параметрами --with-ndbcluster и --with-partition.

    Эта глава обсуждает определяемое пользователем выделение разделов, как выполнено в MySQL 5.1.

    MySQL поддерживает несколько типов выделения разделов, а также подвыделение разделов.

    Методы добавления, удаления и изменения разделов в существующих разбитых на разделы таблицах рассмотрены в " 3.3. Управление разделами".

    Важно: разбитые на разделы таблицы, созданные в MySQL до версии 5.1.6, не могут читаться версией 5.1.6 или позже. Кроме того, таблица INFORMATION_SCHEMA.TABLES не может использоваться, если такие таблицы присутствуют на сервере 5.1.6. Начиная с MySQL 5.1.7, подходящее предупреждающее сообщение сгенерировано о том, что несовместимые разбитые на разделы таблицы были найдены сервером.

    Важно: если Вы используете разбитые на разделы таблицы, которые были созданы в MySQL 5.1.5 или ранее, убедитесь, что изучили список изменений.

    Реализация выделения разделов в MySQL 5.1 все еще подвергается изменениям. Дополнительные ресурсы по теме:

    • MySQL Partitioning Forum

      Это официальный форум обсуждения для тех, кого заинтересовала технология MySQL выделение разделов. Это показывает объявления и модификации от MySQL разработчиков и других. Это контролируется членами Partitioning Development and Documentation Teams.

    • Mikael Ronstrm's Blog

      MySQL Partitioning Architect and Lead Developer Mikael Ronstr├╢m часто регистрирует статьи относительно работы с выделением разделов MySQL и с кластером MySQL.

    • PlanetMySQL

      Место новостей по MySQL, показывающее MySQL-касающиеся блоги, которые должны быть интересными любому, использующему MySQL.

    Двоичная версия MySQL 5.1 теперь доступна с http://dev.mysql.com/downloads/mysql/5.1.html. Однако, для последнего исправления механизма выделения разделов и добавления свойств, Вы можете получать исходник из архива BitKeeper. Чтобы допускать выделению разделов, Вы должны компилировать сервер, используя опцию --with-partition. Если Вы имеете проблемы при компилировании MySQL 5.1 с допускаемым выделением разделов, почитайте форум http://forums.mysql.com/list.php?106 и поищите ответ там.

    3.1. Краткий обзор выделения разделов в MySQL

    Этот раздел обеспечивает концептуальный краткий обзор выделения разделов в MySQL 5.1.

    Стандарт SQL не обеспечивает многого относительно физических аспектов хранения данных. Язык SQL непосредственно предназначен, чтобы работать независимо от любых структур данных или средств, лежащих в основе схем, таблиц, строк или столбцов, с которыми работает. Тем не менее, наиболее продвинутые системы управления базами данных развили некоторые средства определения физического расположения, которое нужно использовать для сохранения специфических частей данных в терминах аппаратных средств или даже файловых систем. В MySQL InnoDB обеспечил понятие пространства таблиц, так что сервер MySQL даже до введения выделения разделов, мог быть сконфигурирован, чтобы использовать различные физические каталоги для сохранения различных баз данных.

    Partitioning берет это понятие и продвигает на шаг далее, позволяя Вам распределить части индивидуальных таблиц по файловым системам согласно правилам, которые Вы можете устанавливать в значительной степени так, как необходимо. В действительности, различные части таблицы сохранены как отдельные таблицы в различных местах. Выбранное пользователем правило, которым выполнен раздел данных, известно как функция выделения разделов, которая в MySQL может быть модулем, простым соответствием набору диапазонов или списков, внутренней или линейной хэш-функцией. Функция выбрана согласно типу выделения разделов, определенному пользователем, и берет как параметр значение обеспеченного пользователем выражения. Это выражение может быть целочисленным значением столбца или функция, действующая на один или большее количество значений столбца, и возвращающая целое число. Значение этого выражения передано функции выделения разделов, которая возвращает целочисленное значение, представляющее номер раздела, в котором эта специфическая запись должна быть сохранена. Эта функция должна быть непостоянная и непроизвольная. Это не может содержать любые запросы, но может использовать фактически любое выражение SQL, которое является допустимым в MySQL, поскольку то выражение возвращает положительное целое число меньше, чем MAXVALUE (самое большое возможное положительное целое число). Примеры выделения разделов функций могут быть найдены в обсуждениях выделения разделов позже в этой главе.

    Это известно как горизонтальное выделение разделов (horizontal partitioning), то есть различные строки таблицы могут быть назначены к различным физическим разделам. MySQL 5.1 не поддерживает вертикальное выделение разделов (vertical partitioning), в котором различные столбцы таблицы назначены различным физическим разделам. Не имеется никаких планов представить вертикальное выделение разделов в MySQL 5.1.

    Выделение разделов включено в -max выпуски MySQL 5.1 (то есть двоичные версии 5.1 -max сформированы с --with-partition). Если MySQL сформирован с выделением разделов, ничто далее не должно быть выполнено, чтобы допустить это (например, никакие специальные записи не требуются в Вашем файле my.cnf). Вы можете определять, поддерживает ли сервер выделение разделов посредством команды SHOW VARIABLES типа этого:

    mysql> SHOW VARIABLES LIKE '%partition%';
    +-------------------+-------+
    | Variable_name     | Value |
    +-------------------+-------+
    | have_partitioning | YES   |
    +-------------------+-------+
    1 row in set (0.00 sec)
    

    Если Вы не видите, что переменная have_partitioning со значением YES перечислена как показано выше в выводе соответствующей SHOW VARIABLES, то Ваша версия MySQL не поддерживает выделение разделов.

    До MySQL 5.1.6 эта переменная была именована have_partition_engine (Глюк #16718).

    Для создания разбитых на разделы таблиц, Вы можете использовать большинство типов хранения, которые обеспечиваются сервером MySQL. MySQL-выделение разделов выполняется в отдельном уровне и может взаимодействовать с любыми из них. В MySQL 5.1 все разделы той же самой разбитой на разделы таблицы должны использовать тот же самый тип памяти, например, Вы не можете использовать MyISAM для одного раздела, а InnoDB для другого. Однако, не имеется ничего предотвращающего Вас от использования различных типов памяти для различных разбитых на разделы таблиц на том же самом сервере MySQL или даже в той же самой базе данных.

    Обратите внимание:: выделение разделов MySQL не может использоваться с типами памяти MERGE или CSV. До MySQL 5.1.6 также было невозможно создать разбитую на разделы таблицу, использующую BLACKHOLE (Глюк #14524). Выделение разделов KEY обеспечивается для использования с NDBCluster, но другие типы определяемого пользователем выделения разделов не обеспечиваются для таблиц Cluster в MySQL 5.1.

    Чтобы использовать специфический тип памяти для разбитой на разделы таблицы, необходимо только использовать опцию [STORAGE] ENGINE точно как для не разбитой на разделы таблицы. Однако, Вы должны иметь в виду, что [STORAGE] ENGINE (и другие параметры таблицы) должен быть перечислен прежде, чем любые параметры выделения разделов используются в инструкции CREATE TABLE. Этот пример показывает, как создать таблицу, которая разбита на 6 разделов по hash и использует тип памяти InnoDB:

    CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
           ENGINE=INNODB PARTITION BY
           HASH(MONTH(tr_date)) PARTITIONS 6;
    

    Обратите внимание, что каждое предложение PARTITION может включать опцию [STORAGE] ENGINE, но в MySQL 5.1 это не имеет никакого эффекта.

    Обратите внимание: выделение разделов применяется ко всем данным и индексам таблицы. Вы не можете выделять разделы только данных и не индексы или наоборот, при этом Вы не можете выделять разделы только части таблицы.

    Данные и индексы для каждого раздела могут быть назначены к специфическому каталогу, используя опции DATA DIRECTORY и INDEX DIRECTORY для предложения PARTITION инструкции CREATE TABLE, используемой чтобы создать разбитую на разделы таблицу. Кроме того, MAX_ROWS и MIN_ROWS могут использоваться, чтобы определить максимальные и минимальные числа строк, соответственно, которые могут быть сохранены в каждом разделе таблицы.

    Некоторые из преимуществ выделения разделов:

    • Можно сохранять большее количество данных в одной таблице, чем может быть записано на одиночном диске или файловой системе.

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

    • Некоторые запросы могут быть значительно оптимизированы в том, что данные, удовлетворяющие предложению WHERE могут быть сохранены только на одном или большем количестве разделов, таким образом исключая любые остающиеся разделы из поиска. Поскольку разделы могут быть изменены после того, как разбитая на разделы таблица была создана, Вы можете реорганизовать данные, чтобы расширить частые запросы, которые, возможно, были медленными, когда схема выделения разделов была сначала установлена. Эта возможность, иногда упоминаемая как сокращение раздела (partition pruning), была выполнена в MySQL 5.1.6.

    Другие выгоды, обычно связываемые с выделением разделов, включены в следующий список. Эти свойства в настоящее время не выполнены в MySQL Partitioning, но высоки в списке приоритетов.

    • Запросы, включающие составные функции типа SUM() и COUNT(), легко могут быть распараллелены. Простым примером такого запроса мог бы быть SELECT salesperson_id, COUNT(orders) as order_total FROM sales GROUP BY salesperson_id;. Запрос может быть выполнен одновременно на каждом разделе, и результат получен просто суммируя результаты, полученные для всех разделов.

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

    3.2. Типы раздела

    Этот раздел обсуждает типы выделения разделов, которые доступны в MySQL 5.1. Они включают:

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

    • LIST partitioning: подобно выделению разделов диапазоном, за исключением того, что раздел выбран основанным на столбцах, соответствующих одному из набора дискретных значений.

    • HASH partitioning: раздел выбран основанным на значении, возвращенном определяемым пользователем выражением, которое функционирует на значениях столбца в строках, которые будут вставлены в таблицу. Функция может состоять из любого выражения, допустимого в MySQL, которое выдает не отрицательное целочисленное значение.

    • KEY partitioning: подобно выделению разделов hash, за исключением того, что обеспечены только один или большее количество столбцов, которые будут оценены, и сервер MySQL обеспечивает собственную хэш-функцию. Эти столбцы могут содержать не целочисленные значения, так как хэш-функция, обеспеченная MySQL, гарантирует целочисленный результат, независимо от типа данных столбца.

    Очень общее использование выделения разделов базы данных должно выделять данные по времени. Некоторые системы баз данных поддерживают явное выделение разделов даты, которое MySQL не выполняет в 5.1. Однако, нетрудно создать в MySQL схемы выделения разделов, основанные на столбцах DATE, TIME, DATETIME или на выражениях, использующих такие столбцы.

    При выделении разделов KEY или LINEAR KEY, Вы можете использовать столбец DATE, TIME или DATETIME как столбец выделения разделов без того, чтобы выполнить любую модификацию значения столбца. Например, эта инструкция создания таблицы совершенно допустима в MySQL:

    CREATE TABLE members (firstname VARCHAR(25) NOT NULL,
                          lastname VARCHAR(25) NOT NULL,
                          username VARCHAR(16) NOT NULL,
                          email VARCHAR(35), joined DATE NOT NULL)
           PARTITION BY KEY(joined) PARTITIONS 6;
    

    Другие типы выделения разделов MySQL, однако, требуют выражения выделения разделов, которое выдает целочисленное значение или NULL. Если Вы желаете использовать дата-основанное выделение разделов RANGE, LIST, HASH или LINEAR HASH, Вы можете просто использовать функцию, которая функционирует на столбце DATE, TIME или DATETIME и возвращает такое значение, как показано здесь:

    CREATE TABLE members (firstname VARCHAR(25) NOT NULL,
                          lastname VARCHAR(25) NOT NULL,
                          username VARCHAR(16) NOT NULL,
                          email VARCHAR(35), joined DATE NOT NULL)
           PARTITION BY RANGE(YEAR(joined)) (
                     PARTITION p0 VALUES LESS THAN (1960),
                     PARTITION p1 VALUES LESS THAN (1970),
                     PARTITION p2 VALUES LESS THAN (1980),
                     PARTITION p3 VALUES LESS THAN (1990),
                     PARTITION p4 VALUES LESS THAN MAXVALUE);
    

    Выделение разделов в MySQL оптимизирован для использования с функциям. TO_DAYS() и YEAR(). Однако, Вы можете использовать другие функции даты и времени, которые возвращают целое число или NULL, типа WEEKDAY(), DAYOFYEAR() или MONTH().

    Важно помнить, что независимо от типа выделения разделов, которое Вы используете, разделы всегда нумеруются автоматически и в той последовательности, в какой созданы, при старте с 0. Когда новая строка вставлена в разбитую на разделы таблицу, это числа раздела, которые используются в идентификации правильного раздела. Например, если Ваша таблица использует 4 раздела, эти разделы пронумерованы 0, 1, 2 и 3. Для типов разделов RANGE и LIST необходимо гарантировать, что имеется раздел, определенный для каждого номера раздела. Для выделения разделов HASH использованная функция пользователя должна возвратить целочисленное значение большее, чем 0. Для выделения разделов KEY об этой проблеме позаботится автоматическая хэш-функция, которую сервер MySQL использует внутренне.

    Имена разделов вообще следуют правилам для других MySQL-идентификаторов, типа тех, что применяются для таблиц и баз данных. Однако, Вы должны обратить внимание, что имена раздела не чувствительны к регистру. Например, следующая инструкция CREATE TABLE терпит неудачу как показано:

    mysql> CREATE TABLE t2 (val INT)
        ->        PARTITION BY LIST(val) (
        ->                  PARTITION mypart VALUES IN (1,3,5),
        ->                  PARTITION MyPart VALUES IN (2,4,6));
    ERROR 1488 (HY000): Duplicate partition name mypart
    

    Сбой происходит потому, что MySQL не видит никакого различия между именами разделов mypart и MyPart.

    Когда Вы определяете число разделов для таблицы, это должно быть выражено как положительный ненулевой целочисленный литерал без начальных нулей, и не может быть выражением типа 0.8E+01 или 6-2, даже если это оценивается как целое число. Начиная с MySQL 5.1.12, десятичные дроби больше не усечены, но взамен отвергнуты полностью.

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

    3.2.1. RANGE Partitioning

    Таблица, которая разбита на разделы диапазоном, разбита на разделы таким способом, которым каждый раздел содержит строки, для которых значение выражения выделения разделов находится внутри данного диапазона. Диапазоны должны быть непрерывны, но не перекрываться и определены, используя оператор VALUES LESS THAN. Для следующих немногих примеров, предположите, что Вы создаете таблицу типа следующей, чтобы сохранить персональные записи для цепочки из 20 видеоклипов, пронумерованных от 1 до 20:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT NOT NULL, store_id INT NOT NULL);
    

    Эта таблица может быть разбита на разделы диапазоном по-разному, в зависимости от Ваших потребностей. Один способ состоит в том, чтобы использовать столбец store_id. Например, Вы могли бы выделять разделы таблицы 4 способами, добавляя предложение PARTITION BY RANGE как показано здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT NOT NULL, store_id INT NOT NULL)
           PARTITION BY RANGE (store_id) (PARTITION p0 VALUES LESS THAN (6),
                                          PARTITION p1 VALUES LESS THAN (11),
                                          PARTITION p2 VALUES LESS THAN (16),
                                          PARTITION p3 VALUES LESS THAN (21));
    

    В этой схеме выделения разделов все строки, соответствующие записям, занимающим номера от 1 до 5, сохранены в разделе p0, от 6 до 10 в p1 и т. д. Обратите внимание, что каждый раздел определен чтобы хранить номера от самого низкого до самого высокого. Это требование синтаксиса PARTITION BY RANGE: Вы можете думать об этом как об аналоге переключателя switch ... case в C или Java в этом отношении.

    Просто определить, что новая строка, содержащая данные (72, 'Michael', 'Widenius', '1998-06-25', NULL, 13), вставлена в раздел p2, но что случается, когда Ваша цепочка, добавляет 21-ю запись? Согласно этой схеме, не имеется никакого правила, которое покрывает строку, с store_id большим чем 20, так что результатом будет ошибка, потому что сервер не знает, где поместить это. Вы можете обойти сбой, используя предложение VALUES LESS THAN в инструкции CREATE TABLE, которая обеспечивает все значения большие, чем явно именованное самое высокое значение:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT NOT NULL, store_id INT NOT NULL)
           PARTITION BY RANGE (store_id) (PARTITION p0 VALUES LESS THAN (6),
                                          PARTITION p1 VALUES LESS THAN (11),
                                          PARTITION p2 VALUES LESS THAN (16),
                                          PARTITION p3 VALUES LESS THAN MAXVALUE);
    

    MAXVALUE представляет самое большое возможное целочисленное значение. Теперь, любые строки, чье значение столбца store_id является большим или равным 16 (самое высокое определенное значение), сохранены в разделе p3. В некоторой точке в будущем, когда число записей увеличится до 25, 30 или больше, Вы можете использовать инструкцию ALTER TABLE, чтобы добавить новые разделы для диапазонов 21-25, 26-30 и т. д.

    В аналогичном режиме Вы могли бы выделять разделы таблицы, основанные на кодах работы служащего, то есть на диапазонах значений столбца job_code. Например, приняв, что коды работы с двумя цифрами используются для регулярных (in-store) рабочих, коды с тремя цифрами используются для ведомства и персонала поддержки, а четырехразрядные коды для позиций управления, Вы могли бы создать разбитую на разделы таблицу, используя:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT NOT NULL, store_id INT NOT NULL)
           PARTITION BY RANGE (job_code) (
                     PARTITION p0 VALUES LESS THAN (100),
                     PARTITION p1 VALUES LESS THAN (1000),
                     PARTITION p2 VALUES LESS THAN (10000));
    

    В этом образце все строки в отношении рабочих in-store были бы сохранены в разделе p0, строки для ведомства и персонала поддержки в p1, а администраторы в разделе p2.

    Также возможно использовать выражение в предложениях VALUES LESS THAN. Однако, MySQL должен быть способен оценить возвращаемое значение выражения как часть сравнения LESS THAN (<).

    Вы можете использовать выражение, основанное на одном из двух столбцов DATE. Например, предположим, что Вы желаете выделить разделы основанные на годе, в котором каждый служащий оставил компанию, то есть значение YEAR(separated). Пример инструкции CREATE TABLE, которая осуществляет такую схему выделения разделов, показывается здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT, store_id INT)
           PARTITION BY RANGE (YEAR(separated)) (
                     PARTITION p0 VALUES LESS THAN (1991),
                     PARTITION p1 VALUES LESS THAN (1996),
                     PARTITION p2 VALUES LESS THAN (2001),
                     PARTITION p3 VALUES LESS THAN MAXVALUE);
    

    В этой схеме для всех служащих, кто оставил работу до 1991, строки сохранены в разделе p0, для периода 1991-1995 в p1, для 1996-2000 в p2, а для любых рабочих, кто оставил фирму после 2000 года в p3.

    Выделение разделов по диапазону особенно полезно когда:

    • Вы хотите удалить старые данные. Если Вы используете схему выделения разделов, показанную выше, Вы можете просто использовать ALTER TABLE employees DROP PARTITION p0; , чтобы удалять все строки в отношении служащих, оставивших работу до 1991. Для таблицы с очень многими строками, это может быть намного более эффективно, чем выполнение запроса DELETE, например, DELETE FROM employees WHERE YEAR(separated) <=1990;.

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

    • Вы часто выполняете запросы, которые зависят непосредственно от столбца, используемого для выделения разделов таблицы. Например, при выполнении запроса типа SELECT COUNT(*) FROM employees WHERE YEAR(separated) = 2000 GROUP BY store_id;, MySQL может быстро определять, что только раздел p2 должен быть просмотрен, потому что остающиеся разделы не могут содержать записи, удовлетворяющие предложению WHERE.

    3.2.2. LIST Partitioning

    Как в выделении разделов RANGE, каждый раздел должен быть явно определен. Главное различие в том, что в выделении разделов списка, каждый раздел определен и выбран основываясь на членстве значения столбца в одном наборе значений списков, а не непрерывных диапазонов значений. Это выполнено, используя PARTITION BY LIST(expr) , где expr значение столбца или выражение, основанное на значении столбца и возврате целочисленного значения, а затем определение каждого раздела посредством VALUES IN (value_list), где value_list разделяемый запятыми список целых чисел.

    Обратите внимание: В MySQL 5.1 возможно соответствовать только списку целых чисел (и возможно NULL) при выделении разделов LIST.

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

    Для примеров ниже будем считать, что базисное определение таблицы, которая будет разбита на разделы обеспечивается инструкцией CREATE TABLE, показанной здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT, store_id INT);
    

    Предположите, что имеются 20 видеоклипов, распределенных среди 4 привилегий, как показано в следующей таблице:

    Область Store ID Numbers
    Север3, 5, 6, 9, 17
    Восток1, 2, 10, 11, 19, 20
    Запад4, 12, 13, 14, 18
    Центр7, 8, 15, 16

    Чтобы выделять разделы таблицы таким способом, чтобы строки для клипов, принадлежащих к той же самой области, были сохранены в том же самом разделе, Вы могли бы использовать инструкцию CREATE TABLE, показанную здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT, store_id INT)
           PARTITION BY LIST(store_id) (
                     PARTITION pNorth VALUES IN (3,5,6,9,17),
                     PARTITION pEast VALUES IN (1,2,10,11,19,20),
                     PARTITION pWest VALUES IN (4,12,13,14,18),
                     PARTITION pCentral VALUES IN (7,8,15,16));
    

    Это облегчает добавление или удаление записи в отношении специфических областей. Например, предположите, что все клипы в западной области проданы другой компании. Все строки в их отношении могут быть удалены запросом ALTER TABLE employees DROP PARTITION pWest;, который может быть выполнен намного более эффективно, чем эквивалентная инструкция DELETE FROM employees WHERE store_id IN (4,12,13,14,18);.

    Как с RANGE и HASH partitioning, если Вы желаете выделить разделы таблицы столбцом, чье значение не целое число или NULL, Вы должны использовать выражение выделения разделов, основанное на том столбце, который возвращает такое значение. Например, предположите, что таблица, содержащая данные определена, как показано здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code CHAR(1), store_id INT);
    

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

    Категория работы или отделКоды работы
    ManagementD, M, O, P
    SalesB, L, S
    TechnicalA, E, G, I, T
    ClericalK, N, Y
    SupportC, F, J, R, V
    UnassignedEmpty

    Так как мы не можем использовать символьные значения в списках, мы должны преобразовать их в целых числа или NULL. Для этой цели мы можем использовать функцию ASCII() на значении столбца. Кроме того, из-за использования различных прикладных программ в разное время коды могут быть верхнего или нижнего регистра, значение empty означает "сейчас не назначен", представлением чего могут быть NULL, пустая строка или пробел. Разбитая на разделы таблица, которая осуществляет эту схему, показывается здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code CHAR(1), store_id INT)
           PARTITION BY LIST(ASCII(UCASE(job_code))) (
                     PARTITION management VALUES IN(68, 77, 79, 80),
                     PARTITION sales VALUES IN(66, 76, 83),
                     PARTITION technical VALUES IN(65, 69, 71, 73, 84),
                     PARTITION clerical VALUES IN(75, 78, 89),
                     PARTITION support VALUES IN(67, 70, 74, 82, 86),
                     PARTITION unassigned VALUES IN(NULL, 0, 32));
    

    Так как выражения не разрешаются в списках значения раздела, Вы должны внести в список коды ASCII для символов, которые должны быть согласованы. Обратите внимание, что ASCII(NULL) вернет NULL.

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

    INSERT INTO employees VALUES
           (224, 'Linus', 'Torvalds', '2002-05-01', '2004-10-12', 'Q', 21);
    

    Сбой происходит, потому что 81 (код ASCII для прописной буквы 'Q') не найден в любом из списков значения используемых, чтобы определить любой из разделов. Не имеется никаких перехватчиков catch-all для list partitions, аналогичных VALUES LESS THAN(MAXVALUE), который приспосабливает значения, не найденные в любом из списков значения. Другими словами, любое значение, которое должно быть согласовано, должно быть найдено в одном из списков значений.

    Как с выделением разделов RANGE, возможно объединить выделение разделов LIST, чтобы произвести составное выделение разделов (подвыделение разделов).

    3.2.3. HASH Partitioning

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

    Чтобы выделять разделы таблицы, использующей выделение разделов HASH, необходимо конкатенировать к инструкции CREATE TABLE предложение PARTITION BY HASH (expr), где expr выражение, которое возвращает целое число. Это может быть просто имя столбца, чей тип является одним из целочисленных типов MySQL. Кроме того, Вы будете, наиболее вероятно, пользоваться предложением PARTITIONS num, где num неотрицательное целое число, представляющее число разделов, на которые таблица должна быть разделена.

    Например, следующая инструкция создает таблицу, которая использует хэширование на столбце store_id и разделена на 4 раздела:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT, store_id INT)
           PARTITION BY HASH(store_id) PARTITIONS 4;
    

    Если Вы не включаете предложение PARTITIONS, числом разделов по умолчанию будет 1. Использование ключевого слова PARTITIONS без числа после него приводит к синтаксической ошибке.

    Вы можете также использовать выражение SQL, которое возвращает целое число для expr. Например, Вы могли бы выделять разделы, основываясь на годе, в котором служащий был нанят. Это может быть выполнено как показано здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT, store_id INT)
           PARTITION BY HASH(YEAR(hired)) PARTITIONS 4;
    

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

    Наиболее эффективная хэш-функция та, которая функционирует на одиночном столбце таблицы, и чье значение увеличивается или уменьшается последовательно со значением столбца, поскольку это учитывает сокращение (pruning) на диапазонах разделов. То есть, выражение изменяется со значением столбца, на котором основано.

    Например, если столбец date_col типа DATE, то выражение TO_DAYS(date_col) изменяется непосредственно со значением date_col, потому что для каждого изменения в значении date_col значение выражения изменяется непротиворечивым способом. Дисперсия выражения YEAR(date_col) относительно date_col не так пряма, как TO_DAYS(date_col), потому что не каждое возможное изменение в date_col производит эквивалентное изменение в YEAR(date_col). Даже в этом случае YEAR(date_col) хороший кандидат на хэш-функцию, потому что это изменяется непосредственно с частью date_col, и не имеется никакого возможного изменения в date_col, которое производит непропорциональное изменение в YEAR(date_col).

    Посредством контраста, предположите, что Вы имеете столбец int_col типа INT. Теперь рассмотрите выражение POW(5-int_col,3)+6. Это было бы плохим выбором для хэш-функции, потому что изменение в значении int_col не произведет пропорциональное изменение в значении выражения. Изменение значения int_col может производить очень разные изменения в значении выражения. Например, изменение int_col с 5 на 6 производит изменение в значении выражения -1, но при изменении значения int_col с 6 на 7 это будет уже -7.

    Другими словами, граф значения столбца против значения выражения более близко следует за прямой строкой по уравнению y=nx, где n некоторая константа, отличная от нуля. Такое выражение лучше подходит для хэширования. Более нелинейный выражение произведет более неравное распределение данных среди разделов.

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

    Когда используется PARTITION BY HASH, MySQL определяет который раздел num использовать, основываясь на модуле результата функции пользователя. Другими словами, для выражения expr раздел, в котором запись сохранена, представляет собой номер раздела N, где N=MOD(expr, num). Например, предположите, что таблица t1 определена следующим образом, чтобы имела 4 раздела:

    CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
           PARTITION BY HASH(YEAR(col3)) PARTITIONS 4;
    

    Если Вы вставляете в t1 запись с '2005-09-15' в col3, то раздел, в котором это будет сохранено, определен следующим образом:

    MOD(YEAR('2005-09-01'),4)=MOD(2005,4)=1
    

    MySQL 5.1 также поддерживает вариант HASH partitioning известного как linear hashing (линейное хэширование) , которое использует более сложный алгоритм для определения размещения новых строк, вставленных в разбитую на разделы таблицу.

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

    Обратите внимание: если таблица, которая будет разбита на разделы, имеет ключ UNIQUE, то любые столбцы, обеспеченные как параметры к HASH функции пользователя или на KEY column_list, должны быть частью того ключа. Исключительная ситуация: это ограничение не относится к таблицам, использующим NDBCluster.

    3.2.3.1. LINEAR HASH Partitioning

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

    Синтаксически единственное различие между выделением разделов линейного хэширования и регулярным хэшированием: добавление ключевого слова LINEAR в предложение PARTITION BY, как показано здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(30),
                            lname VARCHAR(30),
                            hired DATE NOT NULL DEFAULT '1970-01-01',
                            separated DATE NOT NULL DEFAULT '9999-12-31',
                            job_code INT, store_id INT)
           PARTITION BY LINEAR HASH(YEAR(hired)) PARTITIONS 4;
    

    Данный выражением expr раздел, в котором запись сохранена, когда линейное хэширование используется, представляет собой номер раздела N из числа разделов num, где N получен согласно следующему алгоритму:

    1. Находят следующую степень 2 большую, чем num. Назовем это значение V, это может быть вычислено как:

      V=POWER(2, CEILING(LOG(2, num)))
      

      Например, предположите, что num=13. Тогда LOG(2,13)=3.7004397181411. CEILING(3.7004397181411) 4, а V = POWER(2,4) = 3.

    2. Берется N = F(column_list) & (V - 1).

    3. Пока N >= num:

      • Берется V=CEIL(V/2)

      • Берется N = N & (V - 1)

    Например, предположите, что таблица t1 применяет линейное выделение разделов, имеет 6 разделов и создана, используя эту инструкцию:

    CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
           PARTITION BY LINEAR HASH(YEAR(col3)) PARTITIONS 6;
    

    Теперь примите, что Вы хотите вставлять две записи в t1: у одной значение столбца col3 равно '2003-04-14', а у другой составляет '1998-10-19'. Номер раздела для первой из них определен следующим образом:

    V = POWER(2, CEILING( LOG(2,7) )) = 8
    N = YEAR('2003-04-14') & (8-1) = 2003 & 7 = 3
    (3 >= 6 FALSE: запись сохранена в разделе #3
    )
    

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

    V = 8
    N = YEAR('1998-10-19') & (8-1) = 1998 & 7 = 6
    (6 >= 6 TRUE: нужен дополнительный шаг
    )
    N = 6 & CEILING(5 / 2) = 6 & 3 = 2
    (2 >= 6 FALSE: запись сохранена в разделе #2
    )
    

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

    3.2.4. KEY Partitioning

    Выделение разделов ключом подобно выделению разделов хэшем за исключением того, что выделение разделов хэшем использует определяемое пользователем выражение, а хэш-функция для выделения разделов ключом обеспечена MySQL. Здесь MySQL Cluster использует для этой цели MD5(), а для таблиц, использующих другие типы памяти, сервер применяет собственную внутреннюю хэш-функцию, которая основана на том же самом алгоритме, что и PASSWORD().

    Правила синтаксиса для CREATE TABLE ... PARTITION BY KEY подобен правилам для создания таблицы, которая разбита на разделы хэшем. Главные различия состоят в том что:

    • KEY используется вместо HASH.

    • KEY берет только список из одного или большего количества имен столбцов. Начиная с MySQL 5.1.5, если таблица имеет первичный ключ, столбцы, по которым происходит выделение разделов, должны включать хотя бы его часть (или весь ключ).

      Начиная с MySQL 5.1.6, KEY берет список из нуля или большего количества имен столбца. Если никакое имя столбца не определено как ключ выделения разделов, используется первичный ключ таблицы, если он имеется. Например, следующая инструкция CREATE TABLE допустима в MySQL 5.1.6 или позже:

      CREATE TABLE k1 (id INT NOT NULL PRIMARY KEY, name VARCHAR(20))
             PARTITION BY KEY() PARTITIONS 2;
      

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

      CREATE TABLE k1 (id INT NOT NULL, name VARCHAR(20),
                       UNIQUE KEY (id))
             PARTITION BY KEY() PARTITIONS 2;
      

      Однако, если уникальный столбец ключа не был определен как NOT NULL, то предыдущая инструкция будет терпеть неудачу.

      В обоих из этих случаев ключом выделения разделов является столбец id, даже при том, что это не показывается в выводе SHOW CREATE TABLE или в столбце PARTITION_EXPRESSION таблицы INFORMATION_SCHEMA.PARTITIONS.

      В отличие от случая с другими типами выделения разделов, столбцы, используемые для выделения разделов KEY, не ограничены значениями NULL или целым числом. Например, следующая инструкция CREATE TABLE допустима:

      CREATE TABLE tm1 (s1 CHAR(32) PRIMARY KEY)
             PARTITION BY KEY(s1) PARTITIONS 10;
      

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

      Обратите внимание: также начиная с MySQL 5.1.6, таблицы, использующие NDB Cluster неявно разбиты на разделы KEY, используя первичный ключ таблицы как ключ выделения разделов. Когда таблица кластера не имеет никакого явного первичного ключа, применяется скрытый первичный ключ, сгенерированный NDB для каждой таблицы кластера.

      Важно: для таблицы с разделением по ключу, использующей любой тип памяти MySQL, кроме NDB Cluster, Вы не можете выполнять ALTER TABLE DROP PRIMARY KEY, так как это сгенерирует ошибку ERROR 1466 (HY000): Field in list of fields for partition function not found in table. Это не проблема для таблиц MySQL Cluster, которые разбиты на разделы KEY: в таких случаях, таблица реорганизована, используя скрытый первичный ключ для выделения разделов этой таблицы.

    Также возможно выделить разделы таблицы линейным ключом. Имеется простой пример:

    CREATE TABLE tk (col1 INT NOT NULL, col2 CHAR(5), col3 DATE)
           PARTITION BY LINEAR KEY (col1) PARTITIONS 3;
    

    Использование LINEAR имеет тот же самый эффект на KEY, как на выделении разделов HASH с номером раздела, получаемым использованием алгоритма степени двух, а не арифметикой модуля.

    3.2.5. Подвыделение разделов (Subpartitioning)

    Subpartitioning также известно как составное выделение разделов (composite partitioning), что является дальнейшим делением каждого раздела в разбитой на разделы таблице. Например, рассмотрите следующую инструкцию CREATE TABLE:

    CREATE TABLE ts (id INT, purchased DATE)
           PARTITION BY RANGE(YEAR(purchased))
           SUBPARTITION BY HASH(TO_DAYS(purchased))
           SUBPARTITIONS 2 (PARTITION p0 VALUES LESS THAN (1990),
                            PARTITION p1 VALUES LESS THAN (2000),
                            PARTITION p2 VALUES LESS THAN MAXVALUE);
    

    Таблица ts имеет 3 раздела RANGE. Каждый из этих разделов p0, p1 и p2 далее разделен на 2 подраздела. В действительности вся таблица разделена на 3*2=6 разделов. Однако, из-за действия предложения PARTITION BY RANGE первые 2 хранят только записи со значением меньше, чем 1990 в столбце purchased.

    В MySQL 5.1 возможно подвыделить разделы таблиц, которые разбиты на разделы RANGE или LIST. Подразделы могут использовать выделение разделов HASH или KEY. Это также известно как составное выделение разделов.

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

    CREATE TABLE ts (id INT, purchased DATE)
           PARTITION BY RANGE( YEAR(purchased) )
                     SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
           PARTITION p0 VALUES LESS THAN (1990) (
                     SUBPARTITION s0, SUBPARTITION s1),
           PARTITION p1 VALUES LESS THAN (2000) (
                     SUBPARTITION s2, SUBPARTITION s3),
           PARTITION p2 VALUES LESS THAN MAXVALUE (
                     SUBPARTITION s4, SUBPARTITION s5));
    

    Некоторые синтаксические элементы:

    • Каждый раздел должен иметь то же самое число подразделов.

    • Если Вы явно определяете любые подразделы, использующие SUBPARTITION на любом разделе разбитой на разделы таблицы, Вы должны определить их все. Другими словами, следующая инструкция будет терпеть неудачу:

      CREATE TABLE ts (id INT, purchased DATE)
             PARTITION BY RANGE(YEAR(purchased))
                       SUBPARTITION BY HASH(TO_DAYS(purchased)) (
             PARTITION p0 VALUES LESS THAN (1990) (
                       SUBPARTITION s0, SUBPARTITION s1),
             PARTITION p1 VALUES LESS THAN (2000),
             PARTITION p2 VALUES LESS THAN MAXVALUE (
                       SUBPARTITION s2, SUBPARTITION s3));
      

      Эта инструкция свалится даже если добавить предложение SUBPARTITIONS 2.

    • Каждое предложение SUBPARTITION должно включить (как минимум) имя для подраздела. Иначе Вы можете устанавливать любую желательную опцию для подраздела или позволить принимать настройку по умолчанию для этой опции.

    • В MySQL 5.1.7 и ранее имена подразделов должны быть уникальны внутри каждого раздела, но не должны быть уникальны внутри таблицы в целом. Начиная с MySQL 5.1.8, имена подразделов должны быть уникальны для всей таблицы. Например, следующая инструкция CREATE TABLE допустима в MySQL 5.1.8 и позже:

      CREATE TABLE ts (id INT, purchased DATE)
             PARTITION BY RANGE(YEAR(purchased))
                       SUBPARTITION BY HASH(TO_DAYS(purchased)) (
             PARTITION p0 VALUES LESS THAN (1990) (
                       SUBPARTITION s0, SUBPARTITION s1),
             PARTITION p1 VALUES LESS THAN (2000) (
                       SUBPARTITION s2, SUBPARTITION s3),
             PARTITION p2 VALUES LESS THAN MAXVALUE (
                       SUBPARTITION s4, SUBPARTITION s5));
      

      Предыдущая инструкция также допустима для версий MySQL до 5.1.8.

    Подразделы могут использоваться с особенно большими таблицами, чтобы распределить данные и индексы на много дисков. Предположите, что Вы имеете 6 дисков, установленные как /disk0, /disk1, /disk2 и т. д. Теперь рассмотрите следующий пример:

    CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE(YEAR(purchased))
           SUBPARTITION BY HASH(TO_DAYS(purchased)) (
           PARTITION p0 VALUES LESS THAN (1990) (
           SUBPARTITION s0 DATA DIRECTORY = '/disk0/data'
                           INDEX DIRECTORY = '/disk0/idx',
           SUBPARTITION s1 DATA DIRECTORY = '/disk1/data'
                           INDEX DIRECTORY = '/disk1/idx'),
           PARTITION p1 VALUES LESS THAN (2000) (
           SUBPARTITION s2 DATA DIRECTORY = '/disk2/data'
                           INDEX DIRECTORY = '/disk2/idx',
           SUBPARTITION s3 DATA DIRECTORY = '/disk3/data'
                           INDEX DIRECTORY = '/disk3/idx'),
           PARTITION p2 VALUES LESS THAN MAXVALUE (SUBPARTITION s4
                        DATA DIRECTORY = '/disk4/data'
                        INDEX DIRECTORY = '/disk4/idx',
           SUBPARTITION s5 DATA DIRECTORY = '/disk5/data'
                        INDEX DIRECTORY = '/disk5/idx'));
    

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

    CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE(YEAR(purchased))
           SUBPARTITION BY HASH(TO_DAYS(purchased)) (
           PARTITION p0 VALUES LESS THAN (1990) (
           SUBPARTITION s0a DATA DIRECTORY = '/disk0' INDEX DIRECTORY='/disk1',
           SUBPARTITION s0b DATA DIRECTORY = '/disk2' INDEX DIRECTORY='/disk3'),
           PARTITION p1 VALUES LESS THAN (2000) (
           SUBPARTITION s1a DATA DIRECTORY = '/disk4/data'
                            INDEX DIRECTORY = '/disk4/idx',
           SUBPARTITION s1b DATA DIRECTORY = '/disk5/data'
                            INDEX DIRECTORY = '/disk5/idx'),
           PARTITION p2 VALUES LESS THAN MAXVALUE (
                        SUBPARTITION s2a, SUBPARTITION s2b));
    

    Здесь хранение следующее:

    • Строки с датами purchased до 1990 занимают обширное количество места, поэтому поделены 4 путями: с отдельным диском, специализированным для данных, и с дополнительным диском для индексов для каждого из двух подразделов (s0a и s0b), входящих в раздел p0. Другими словами:

      • Данные для подраздела s0a сохранены на /disk0.

      • Индексы для подраздела s0a сохранены на /disk1.

      • Данные для подраздела s0b сохранены на /disk2.

      • Индексы для подраздела s0b сохранены на /disk3.

    • Строки, содержащие даты в пределах от 1990 до 1999 (раздел p1) не требуют так много памяти, как даты до 1990. Они размазаны между 2 дисками (/disk4 и /disk5):

      • Данные и индексы, принадлежащие первому подразделу (s1a) раздела p1, сохранены на /disk4: данные в /disk4/data, а индексы в /disk4/idx.

      • Данные и индексы, принадлежащие второму подразделу (s1b) раздела p1, сохранены на /disk5: данные в /disk5/data, а индексы в /disk5/idx.

    • Строки, отражающие даты с года 2000 до текущей (раздел p2), не занимают так много места, как любой из двух предыдущих диапазонов. В настоящее время достаточно сохранить всех их в заданном по умолчанию расположении.

      В будущем, когда число purchases в течение десятилетия, начинающегося годом 2000, вырастет до отметки, где заданное по умолчанию расположение больше не обеспечивает достаточного места, соответствующие строки могут перемещаться, используя ALTER TABLE ... REORGANIZE PARTITION.

    3.2.6. Как выделитель разделов в MySQL обрабатывает значения NULL

    Выделение разделов в MySQL не делает ничего, чтобы отвергнуть NULL как значение выражения выделения разделов независимо от того, является ли это значением столбца или обеспеченного пользователем выражения. Даже разрешается использовать NULL как значение выражения, которое должно выдать целое число, но важно иметь в виду, что NULL числом не является. Начиная с версии 5.1.8, MySQL обрабатывает NULL как будто он меньше, чем любое не нулевое значение, точно как делает ORDER BY.

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

    mysql> CREATE TABLE t1 (c1 INT, c2 VARCHAR(20))
        ->        PARTITION BY RANGE(c1) (
        ->                  PARTITION p0 VALUES LESS THAN (0),
        ->                  PARTITION p1 VALUES LESS THAN (10),
        ->                  PARTITION p2 VALUES LESS THAN MAXVALUE);
    Query OK, 0 rows affected (0.09 sec)
    
    mysql> CREATE TABLE t1 (c1 INT, c2 VARCHAR(20))
        ->        PARTITION BY RANGE(c1) (
        ->                  PARTITION p0 VALUES LESS THAN (-5),
        ->                  PARTITION p1 VALUES LESS THAN (0),
        ->                  PARTITION p1 VALUES LESS THAN (10),
        ->                  PARTITION p2 VALUES LESS THAN MAXVALUE);
    Query OK, 0 rows affected (0.09 sec)
    mysql> INSERT INTO t1 VALUES (NULL, 'mothra');
    Query OK, 1 row affected (0.00 sec)
    mysql> INSERT INTO t2 VALUES (NULL, 'mothra');
    Query OK, 1 row affected (0.00 sec)
    
    mysql> SELECT * FROM t1;
    +------+--------+
    | id   | name   |
    +------+--------+
    | NULL | mothra |
    +------+--------+
    1 row in set (0.00 sec)
    
    mysql> SELECT * FROM t2;
    +------+--------+
    | id   | name   |
    +------+--------+
    | NULL | mothra |
    +------+--------+
    1 row in set (0.00 sec)
    

    Вы можете видеть, в который раздел строки сохранены, осматривая файловую систему и сравнивая размеры .MYD-файлов:

    /var/lib/mysql/test> ls -l *.MYD
    -rw-rw---- 1 mysql mysql 20 2006-03-10 03:27 t1#P#p0.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 03:17 t1#P#p1.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 03:17 t1#P#p2.MYD
    -rw-rw---- 1 mysql mysql 20 2006-03-10 03:27 t2#P#p0.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 03:17 t2#P#p1.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 03:17 t2#P#p2.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 03:17 t2#P#p3.MYD
    

    Файлы разделов именованы согласно формату table_name#P#partition_name .extension так, чтобы t1#P#p0.MYD был файлом, в котором сохранены данные, принадлежащие к разделу p0 таблицы t1. Обратите внимание: до MySQL 5.1.5, эти файлы были бы именованы соответственно t1_p0.MYD и t2_p0.MYD.

    Вы можете также показывать, что эти строки были сохранены в самом низком разделе каждой таблицы, удаляя эти разделы, а затем делая повторный запуск инструкций SELECT:

    mysql> ALTER TABLE t1 DROP PARTITION p0;
    Query OK, 0 rows affected (0.16 sec)
    mysql> ALTER TABLE t2 DROP PARTITION p0;
    Query OK, 0 rows affected (0.16 sec)
    mysql> SELECT * FROM t1;
    Empty set (0.00 sec)
    mysql> SELECT * FROM t2;
    Empty set (0.00 sec)
    

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

    CREATE TABLE tndate (id INT, dt DATE) PARTITION BY RANGE(YEAR(dt)) (
           PARTITION p0 VALUES LESS THAN (1990),
           PARTITION p1 VALUES LESS THAN (2000),
           PARTITION p2 VALUES LESS THAN MAXVALUE);
    

    Как с другими функциями MySQL, YEAR(NULL) вернет NULL. Строка со значением NULL столбца dt обрабатывается, как если бы выражение выделения разделов было оценено к значению меньше, чем любое другое значение, и так вставлено в раздел p0.

    Таблица, которая разбита на разделы LIST допускает значения NULL если (и только если!) один из разделов определен, используя список значений, который содержит NULL. Таблица, разбитая на разделы LIST, которая явно не использует NULL в списке значений, отклоняет строки, приводящие к значению NULL для выражения выделения разделов, как показано в этом примере:

    mysql> CREATE TABLE ts1 (c1 INT, c2 VARCHAR(20))
        ->        PARTITION BY LIST(c1) (
        ->                  PARTITION p0 VALUES IN (0, 3, 6),
        ->                  PARTITION p1 VALUES IN (1, 4, 7),
        ->                  PARTITION p2 VALUES IN (2, 5, 8));
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> INSERT INTO ts1 VALUES (9, 'mothra');
    ERROR 1504 (HY000): Table has no partition for value 9
    mysql> INSERT INTO ts1 VALUES (NULL, 'mothra');
    ERROR 1504 (HY000): Table has no partition for value NULL
    

    Только строки, имеющие значение c1 между 0 и 8 включительно, могут быть вставлены в ts1. NULL выходит за пределы этого диапазона точно так же, как число 9. Мы можем создавать таблицы ts2 и ts3 и списки значений, содержащие NULL, как показано здесь:

    mysql> CREATE TABLE ts2 (c1 INT, c2 VARCHAR(20))
        ->        PARTITION BY LIST(c1) (
        ->                  PARTITION p0 VALUES IN (0, 3, 6),
        ->                  PARTITION p1 VALUES IN (1, 4, 7),
        ->                  PARTITION p2 VALUES IN (2, 5, 8),
        ->                  PARTITION p3 VALUES IN (NULL));
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> CREATE TABLE ts3 (c1 INT, c2 VARCHAR(20))
        ->        PARTITION BY LIST(c1) (
        ->                  PARTITION p0 VALUES IN (0, 3, 6),
        ->                  PARTITION p1 VALUES IN (1, 4, 7, NULL),
        ->                  PARTITION p2 VALUES IN (2, 5, 8));
    Query OK, 0 rows affected (0.01 sec)
    

    При определении значения для выделения разделов, Вы можете обрабатывать NULL точно как любое другое значение, и допустимы VALUES IN (NULL) и VALUES IN (1, 4, 7, NULL) (равно как и VALUES IN (1, NULL, 4, 7), VALUES IN (NULL, 1, 4, 7) и тому подобное). Вы можете вставлять строку, имеющую NULL для столбца c1 в каждую из таблиц ts2 и ts3:

    mysql> INSERT INTO ts2 VALUES (NULL, 'mothra');
    Query OK, 1 row affected (0.00 sec)
    mysql> INSERT INTO ts3 VALUES (NULL, 'mothra');
    Query OK, 1 row affected (0.00 sec)
    

    Осматривая файловую систему, Вы можете проверить, что первая из этих инструкций вставила новую строку в раздел p3 таблицы ts2, а вторая инструкция вставила новую строку в раздел p1 таблицы ts3:

    /var/lib/mysql/test> ls -l ts2*.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 10:35 ts2#P#p0.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 10:35 ts2#P#p1.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 10:35 ts2#P#p2.MYD
    -rw-rw---- 1 mysql mysql 20 2006-03-10 10:35 ts2#P#p3.MYD
    
    /var/lib/mysql/test> ls -l ts3*.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 10:36 ts3#P#p0.MYD
    -rw-rw---- 1 mysql mysql 20 2006-03-10 10:36 ts3#P#p1.MYD
    -rw-rw---- 1 mysql mysql 0 2006-03-10 10:36 ts3#P#p2.MYD
    

    Как в более ранних примерах, мы принимаем использование оболочки bash в операционной системе для Unix для списка файлов. Например, если Вы используете оболочку DOS в операционной системе Windows эквивалент последнего вывода мог быть получен, выполняя команду dir ts3*.MYD в каталоге C:\Program Files\MySQL\MySQL Server 5.1\data\test.

    Как показано ранее в этом разделе, Вы можете также проверять, которые разделы использовались для сохранения значений удаляя их, а затем выполняя SELECT.

    NULL обработан несколько по-другому для таблиц, разбитых на разделы HASH или KEY. В этих случаях любое выражение раздела, которое выдает значение NULL, обрабатывается, как если бы возвращаемое значение было нулевым. Мы можем проверять это поведение, исследуя эффекты в файловой системе от создания таблицы, разбитой на разделы HASH и начальной загрузкой с записью, содержащей соответствующие значения. Предположите, что Вы имеете таблицу th, созданную в базе данных test, используя эту инструкцию:

    mysql> CREATE TABLE th (c1 INT, c2 VARCHAR(20))
        ->        PARTITION BY HASH(c1) PARTITIONS 2;
    Query OK, 0 rows affected (0.00 sec)
    

    При принятии установки RPM MySQL под Linux, эта инструкция создает два .MYD-файла в /var/lib/mysql/test, которые могут просматриваться в оболочке bash следующим образом:

    /var/lib/mysql/test> ls th*.MYD -l
    -rw-rw---- 1 mysql mysql 0 2005-11-04 18:41 th#P#p0.MYD
    -rw-rw---- 1 mysql mysql 0 2005-11-04 18:41 th#P#p1.MYD
    

    Обратите внимание, что размер каждого файла 0 байтов. Теперь вставьте в th строку, чей столбец c1 является NULL, и проверьте, что эта строка была вставлена:

    mysql> INSERT INTO th VALUES (NULL, 'mothra');
    Query OK, 1 row affected (0.00 sec)
    mysql> SELECT * FROM th;
    +------+---------+
    | c1   | c2      |
    +------+---------+
    | NULL | mothra  |
    +------+---------+
    1 row in set (0.01 sec)
    

    Заметьте, что для любого целого числа N значение NULL MOD N всегда NULL. Для таблиц, которые разбиты на разделы HASH илм KEY, этот результат обрабатывается для определения правильного раздела как 0. При возврате к оболочке системы, мы можем видеть, что значение было вставлено в первый раздел (по умолчанию p0), выводя файлы данных еще раз:

    var/lib/mysql/test> ls *.MYD -l
    -rw-rw---- 1 mysql mysql 20 2005-11-04 18:44 th#P#p0.MYD
    -rw-rw---- 1 mysql mysql  0 2005-11-04 18:41 th#P#p1.MYD
    

    Вы можете видеть, что инструкция INSERT изменила только файл th#P#p0.MYD (увеличение размера на диске) без того, чтобы воздействовать на другой файл данных.

    Важно: до MySQL 5.1.8 выделение разделов по RANGE значение выражения выделения разделов NULL работало как 0 (единственный способ обходить это должен был разработать таблицы так, чтобы не позволить пустые указатели, обычно объявляя столбцы NOT NULL). Если Вы имеете схему выделения разделов RANGE, которая зависит от этого более раннего поведения, Вы будете должны заново выполнить это при обновлении до MySQL 5.1.8 или позже.

    3.3. Управление разделами

    MySQL 5.1 обеспечивает ряд способов изменить разбитые на разделы таблицы. Возможно добавлять, удалять, переопределять, объединять или расчленять существующие разделы. Все эти действия могут быть выполнены, используя расширения выделения разделов к команде ALTER TABLE. Имеются также способы получить информацию относительно разбитых на разделы таблиц и разделов.

    Обратите внимание: в MySQL 5.1 все разделы разбитой на разделы таблицы должны иметь то же самое число подразделов, и невозможно изменить подвыделение разделов, если только таблица была создана.

    Инструкция ALTER TABLE ... PARTITION BY ... доступна с MySQL 5.1.6, предварительно, в MySQL 5.1, это было принято как допустимый синтаксис, но инструкция не делала ничего.

    Чтобы изменять схему выделения разделов таблицы, необходимо использовать команду ALTER TABLE с предложением partition_options. Это предложение имеет тот же самый синтаксис, как то, что используется с CREATE TABLE для создания разбитой на разделы таблицы, и всегда начинается с ключевых слов PARTITION BY. Например, предположите, что Вы имеете таблицу, разбитую на разделы диапазоном, использующим следующую инструкцию CREATE TABLE:

    CREATE TABLE trb3 (id INT, name VARCHAR(50), purchased DATE)
           PARTITION BY RANGE(YEAR(purchased)) (
                     PARTITION p0 VALUES LESS THAN (1990),
                     PARTITION p1 VALUES LESS THAN (1995),
                     PARTITION p2 VALUES LESS THAN (2000),
                     PARTITION p3 VALUES LESS THAN (2005));
    

    Чтобы заново выделять разделы этой таблицы так, чтобы это было разбито на разделы ключом на два раздела, использующие значение столбца id как основание для ключа, Вы можете использовать эту инструкцию:

    ALTER TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2;
    

    Это имеет тот же самый эффект на структуре таблицы как удаление таблицы и создания ее вновь, используя CREATE TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2;.

    Важно: в MySQL 5.1.7 и ранее ALTER TABLE ... ENGINE = ... удаляет все выделение разделов из обрабатываемой таблицы. Начиная с MySQL 5.1.8, этот оператор меняет только тип памяти, используемый таблицей, и оставляет схему выделения разделов таблицы неповрежденной. С MySQL 5.1.8 применяйте ALTER TABLE ... REMOVE PARTITIONING, чтобы удалить выделение разделов таблицы.

    3.3.1. Управление разделами RANGE и LIST

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

    Удаление раздела из таблицы, которая разбита на разделы RANGE или LIST может быть выполнено, используя инструкцию ALTER TABLE с предложением DROP PARTITION. Имеется базисный пример, который предполагает, что Вы уже создали таблицу, которая разбита на разделы диапазоном и затем заполняется 10 записями, использующими следующие инструкции CREATE TABLE и INSERT:

    mysql> CREATE TABLE tr (id INT, name VARCHAR(50), purchased DATE)
        ->        PARTITION BY RANGE(YEAR(purchased)) (
        ->                  PARTITION p0 VALUES LESS THAN (1990),
        ->                  PARTITION p1 VALUES LESS THAN (1995),
        ->                  PARTITION p2 VALUES LESS THAN (2000),
        ->                  PARTITION p3 VALUES LESS THAN (2005));
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> INSERT INTO tr VALUES
        ->        (1, 'desk organiser', '2003-10-15'),
        ->        (2, 'CD player', '1993-11-05'),
        ->        (3, 'TV set', '1996-03-10'),
        ->        (4, 'bookcase', '1982-01-10'),
        ->        (5, 'exercise bike', '2004-05-09'),
        ->        (6, 'sofa', '1987-06-05'),
        ->        (7, 'popcorn maker', '2001-11-22'),
        ->        (8, 'aquarium', '1992-08-04'),
        ->        (9, 'study desk', '1984-09-16'),
        ->        (10, 'lava lamp', '1998-12-25');
    Query OK, 10 rows affected (0.01 sec)
    

    Вы можете видеть, которые элементы должны быть вставлены в раздел p2 как показано здесь:

    mysql> SELECT * FROM tr
        ->          WHERE purchased BETWEEN '1995-01-01' AND
        ->          '1999-12-31';
    +----+-----------+------------+
    | id | name      | purchased  |
    +----+-----------+------------+
    |  3 | TV set    | 1996-03-10 |
    | 10 | lava lamp | 1998-12-25 |
    +----+-----------+------------+
    2 rows in set (0.00 sec)
    

    Чтобы удалить раздел p2, выполните следующую команду:

    mysql> ALTER TABLE tr DROP PARTITION p2;
    Query OK, 0 rows affected (0.03 sec)
    

    Обратите внимание: в MySQL 5.1 NDB Cluster не поддерживает ALTER TABLE ... DROP PARTITION. Это, однако, поддерживает другие связанные с выделением разделов расширения ALTER TABLE, которые описаны в этой главе.

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

    mysql> SELECT * FROM tr WHERE purchased
        ->          BETWEEN '1995-01-01' AND '1999-12-31';
    Empty set (0.00 sec)
    

    Из-за этого в MySQL 5.1.10 было добавлено требование, что Вы имеете привилегию DROP для таблицы прежде, чем Вы сможете выполнять ALTER TABLE ... DROP PARTITION на этой таблице.

    Если Вы желаете удалить все данные из всех разделов при сохранении определения таблицы и схемы выделения разделов, используйте команду TRUNCATE TABLE.

    Если Вы предполагаете изменять выделение разделов таблицы без потерь данных, используйте вместо этого ALTER TABLE ... REORGANIZE PARTITION.

    Если Вы теперь выполняете команду SHOW CREATE TABLE, Вы можете видеть, как выделение разделов таблицы было изменено:

    mysql> SHOW CREATE TABLE tr\G
    *************************** 1. row ***************************
    Table: tr
    Create Table: CREATE TABLE `tr` (`id` int(11) default NULL,
                                     `name` varchar(50) default NULL,
                                     `purchased` date default NULL)
                                     ENGINE=MyISAM DEFAULT CHARSET=latin1
           PARTITION BY RANGE (YEAR(purchased)) (
                     PARTITION p0 VALUES LESS THAN (1990) ENGINE = MyISAM,
                     PARTITION p1 VALUES LESS THAN (1995) ENGINE = MyISAM,
                     PARTITION p3 VALUES LESS THAN (2005) ENGINE = MyISAM)
    1 row in set (0.01 sec)
    

    Когда Вы вставляете новые строки в измененную таблицу со значениями столбца purchased между '1995-01-01' и '2004-12-31' включительно, те строки будут сохранены в разделе p3. Вы можете проверять этот факт следующим образом:

    mysql> INSERT INTO tr VALUES (11, 'pencil holder', '1995-07-12');
    Query OK, 1 row affected (0.00 sec)
    mysql> SELECT * FROM tr WHERE purchased
        ->          BETWEEN '1995-01-01' AND '2004-12-31';
    +----+----------------+------------+
    | id | name           | purchased  |
    +----+----------------+------------+
    | 11 | pencil holder  | 1995-07-12 |
    |  1 | desk organiser | 2003-10-15 |
    |  5 | exercise bike  | 2004-05-09 |
    |  7 | popcorn maker  | 2001-11-22 |
    +----+----------------+------------+
    4 rows in set (0.00 sec)
    
    mysql> ALTER TABLE tr DROP PARTITION p3;
    Query OK, 0 rows affected (0.03 sec)
    mysql> SELECT * FROM tr WHERE purchased
        ->          BETWEEN '1995-01-01' AND '2004-12-31';
    Empty set (0.00 sec)
    

    Обратите внимание, что число строк, удаленных из таблицы в результате ALTER TABLE ... DROP PARTITION не сообщено сервером, поскольку это было бы эквивалентом запроса DELETE.

    Удаление разделов LIST использует такой же синтаксис same ALTER TABLE ... DROP PARTITION, как и для RANGE. Однако, имеется одно важное различие в эффекте, который это имеет на вашем использовании таблицы позже: Вы больше не можете вставлять в таблицу никакие строки, имеющие любое из значений, которые были включены в список значения, определяющие удаленный раздел.

    Чтобы добавлять новый диапазон или раздел списка к предварительно разбитой на разделы таблице, используйте инструкцию ALTER TABLE ... ADD PARTITION. Для таблиц, которые разбиты на разделы RANGE, это может использоваться, чтобы добавить новый диапазон к концу списка существующих разделов. Например, предположите, что Вы имеете разбитую на разделы таблицу, содержащую данные членства для Вашей организации, которая определена следующим образом:

    CREATE TABLE members (id INT, fname VARCHAR(25), lname VARCHAR(25), dob DATE)
           PARTITION BY RANGE(YEAR(dob)) (PARTITION p0 VALUES LESS THAN (1970),
                                          PARTITION p1 VALUES LESS THAN (1980),
                                          PARTITION p2 VALUES LESS THAN (1990));
    

    Предположите далее, что минимальный возраст для элементов 3. Поскольку календарь приближается к концу 2005, Вы понимаете, что Вы будете скоро допускать элементы, которые были рождены в 1990 (и позже в последующих годах). Вы можете изменять таблицу элементов, чтобыразместить новые элементы members, рожденные в годах 1990-1999 как показано здесь:

    ALTER TABLE ADD PARTITION (PARTITION p3 VALUES LESS THAN (2000));
    

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

    mysql> ALTER TABLE members
        ->       ADD PARTITION (PARTITION p3 VALUES LESS THAN (1960));
    ERROR 1463 (HY000): VALUES LESS THAN value must be strictly
               increasing for each partition
    

    В подобном режиме Вы можете добавлять новые разделы к таблице, которая разбита на разделы LIST. Например, данная таблица определена подобно этому:

    CREATE TABLE tt (id INT, data INT)
           PARTITION BY LIST(data) (PARTITION p0 VALUES IN (5, 10, 15),
                                    PARTITION p1 VALUES IN (6, 12, 18));
    

    Вы можете добавлять новый раздел, чтобы сохранить строки, имеющие значения столбца data 7, 14 и 21 как показано здесь:

    ALTER TABLE tt ADD PARTITION (PARTITION p2 VALUES IN (7, 14, 21));
    

    Обратите внимание, что Вы не можете добавлять новый раздел LIST, включающий любые значения, которые уже включены в список значений существующего раздела (сервер не поймет, в какой именно раздел ему дописывать данные). Если Вы пытаетесь сделать так, выйдет ошибка:

    mysql> ALTER TABLE tt ADD PARTITION
        -> (PARTITION np VALUES IN (4, 8, 12));
    ERROR 1465 (HY000): Multiple definition of same constant ┬╗
    in list partitioning
    

    Потому что любые строки со значением столбца data 12 уже были назначены в раздел p1, Вы не можете создавать новый раздел в таблице tt, который включает 12 в список значения. Чтобы выполнять это, Вы могли бы удалить p1, добавить np, а затем новый p1 с изменяемым определением. Однако, как сказано ранее, это привело бы к потере всех данных, сохраненных в p1, и это часто имеет место. Другое решение: сделать копию таблицы с новым выделением разделов и скопировать данные в нее, используя CREATE TABLE ... SELECT ..., затем удалить старую таблицу и переименовать новую, но это могло бы быть очень долго, когда имеешь дело с большими количествами данных. Это также не может быть возможно в ситуациях, где высокая доступность является требованием.

    Начиная с MySQL 5.1.6, Вы можете добавлять много разделов в одиночной команде ALTER TABLE ... ADD PARTITION, как показано здесь:

    CREATE TABLE employees (id INT NOT NULL, fname VARCHAR(50) NOT NULL,
                            lname VARCHAR(50) NOT NULL, hired DATE NOT NULL)
           PARTITION BY RANGE(YEAR(hired)) (
                     PARTITION p1 VALUES LESS THAN (1991),
                     PARTITION p2 VALUES LESS THAN (1996),
                     PARTITION p3 VALUES LESS THAN (2001),
                     PARTITION p4 VALUES LESS THAN (2005));
    ALTER TABLE employees ADD PARTITION (PARTITION p5 VALUES LESS THAN (2010),
                                         PARTITION p6 VALUES LESS THAN MAXVALUE);
    

    Реализация выделения разделов в MySQL обеспечивает способы переопределить разделы без потерь данных. Выберите таблицу элементов members, которая теперь определена как показано здесь:

    mysql> SHOW CREATE TABLE members\G
    *************************** 1. row ***************************
    Table: members
    Create Table: CREATE TABLE `members` (`id` int(11) default NULL,
                                          `fname` varchar(25) default NULL,
                                          `lname` varchar(25) default NULL,
                                          `dob` date default NULL)
                                          ENGINE=MyISAM DEFAULT CHARSET=latin1
           PARTITION BY RANGE (YEAR(dob)) (
                     PARTITION p0 VALUES LESS THAN (1970) ENGINE = MyISAM,
                     PARTITION p1 VALUES LESS THAN (1980) ENGINE = MyISAM,
                     PARTITION p2 VALUES LESS THAN (1990) ENGINE = MyISAM.
                     PARTITION p3 VALUES LESS THAN (2000) ENGINE = MyISAM)
    

    Предположите, что Вы хотели бы переместить все строки, представляющие элементы, рожденные перед 1960 в отдельный раздел. Мы уже видели, что это не может быть выполнено, используя ALTER TABLE ... ADD PARTITION. Однако, Вы можете использовать другое связанное с разделом расширение ALTER TABLE, чтобы выполнить это:

    ALTER TABLE members REORGANIZE PARTITION p0 INTO (
          PARTITION s0 VALUES LESS THAN (1960),
          PARTITION s1 VALUES LESS THAN (1970));
    

    В действительности эти команды разделяют раздел p0 на два новых раздела s0 и s1. Это также перемещает данные, которые были сохранены в p0, в новые разделы согласно правилам, воплощенным в двух предложениях PARTITION ... VALUES ..., так, чтобы s0 содержал только те записи, для которых YEAR(dob) меньше, чем 1960 и s1 хранил те строки, в которых YEAR(dob) является большим чем или равным 1960, но меньше чем 1970.

    Предложение REORGANIZE PARTITION может также использоваться для объединения смежных разделов. Вы можете возвращать таблицу элементов members к предыдущему выделению разделов, как показано здесь:

    ALTER TABLE members REORGANIZE PARTITION s0,s1 INTO (
          PARTITION p0 VALUES LESS THAN (1970));
    

    Никакие данные не потеряны при разбиении или объединении разделов, использующих REORGANIZE PARTITION. При выполнении вышеупомянутой инструкции MySQL перемещает все записи, которые были сохранены в разделах s0 и s1 в раздел p0.

    Общий синтаксис для REORGANIZE PARTITION:

    ALTER TABLE tbl_name
          REORGANIZE PARTITION partition_list
          INTO (partition_definitions);
    

    Здесь tbl_name имя разбитой на разделы таблицы, partition_list разделяемый запятыми список имен одного или большего количества существующих разделов, которые будут изменены. partition_definitions разделяемый запятыми список новых определений разделов, которые следуют тем же самым правилам, что касаются списка partition_definitions, используемого в CREATE TABLE. Должно быть отмечено, что Вы не ограничены объединением нескольких разделов в один или разбиением одного раздела на много, когда используете REORGANIZE PARTITION. Например, Вы можете реорганизовать все четыре раздела таблицы элементов members в два следующим образом:

    ALTER TABLE members REORGANIZE PARTITION p0,p1,p2,p3 INTO (
          PARTITION m0 VALUES LESS THAN (1980),
          PARTITION m1 VALUES LESS THAN (2000));
    

    
    Вы можете также использовать REORGANIZE PARTITION с таблицами,
    которые разбиты на разделы LIST. Вернемся к проблеме добавления
    нового раздела к разбитой на разделы списком таблице tt и тому,
    что новый раздел имел значение, которое было уже представлено в списке
    значений одного из существующих разделов. Мы можем обрабатывать это, добавляя
    раздел, который содержит только не находящиеся в противоречии значения, а
    затем реорганизуя новый и существующий разделы так, чтобы значение, которое
    было сохранено в существующем, переместилось в новый:

    ALTER TABLE tt ADD PARTITION (PARTITION np VALUES IN (4, 8));
    ALTER TABLE tt REORGANIZE PARTITION p1,np INTO (
          PARTITION p1 VALUES IN (6, 18),
          PARTITION np VALUES in (4, 8, 12));
    

    Имеются некоторые ключевые точки, которые следует иметь в виду, когда используете ALTER TABLE ... REORGANIZE PARTITION, чтобы заново выделить разделы таблиц, которые разбиты на разделы RANGE или LIST:

    • Предложения PARTITION используемые, чтобы определить новую схему выделения разделов, подчинены тем же самым правилам, какие использовали с инструкцией CREATE TABLE.

      Наиболее важно, Вы должны не забыть, что новая схема выделения разделов не может иметь любые диапазоны перекрывания (применяется к таблицам, разбитым на разделы RANGE) или наборов значений (при реорганизации таблиц, разбитых на разделы LIST).

      Обратите внимание: до MySQL 5.1.4 Вы не могли бы многократно использовать имена существующих разделов в предложении INTO, даже когда те разделы удалялись удалялись или переопределялись.

    • Комбинация разделов в списке partition_definitions должна объявить тот же самый диапазон или полный набор значений, что и объединенные разделы, именованные в partition_list.

      Например, в таблице элементов members, используемой в этом разделе, выделяются разделы p1 и p2, которые вместе покрывают годы с 1980 по 1999. Следовательно, любая реорганизация этих двух разделов должна покрыть тот же самый диапазон полных лет.

    • Для таблиц, разбитых на разделы RANGE Вы можете реорганизовать только смежные разделы. Вы не можете перескакивать над разделами диапазона.

      Например, Вы не могли бы реорганизовать таблицу элементов members, используемую в этом разделе, используя инструкцию, начинающуюся ALTER TABLE members REORGANIZE PARTITION p0, p2 INTO ..., поскольку p0 покрывает годы до 1970, а p2 годы с 1990 по 1999 включительно, и таким образом это не смежные разделы.

    • Вы не можете использовать REORGANIZE PARTITION, чтобы изменить тип выделения разделов таблицы, то есть Вы не можете (например) изменять разделы RANGE на HASH или наоборот. Вы также не можете использовать эту команду, чтобы изменить выражение выделения разделов или столбец. Чтобы выполнять любую из этих задач без того, чтобы удалить и вновь создать таблицу, Вы можете использовать ALTER TABLE ... PARTITION BY .... Например:

      ALTER TABLE members PARTITION BY HASH(YEAR(dob)) PARTITIONS 8;
      

    3.3.2. Управление разделами KEY и HASH

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

    Вы не можете удалять разделы из таблиц, которые разбиты на разделы HASH или KEY таким же образом, каким Вы можете удалять их из таблиц, которые разбиты на разделы RANGE или LIST. Однако, Вы можете объединять разделы HASH или KEY, используя команду ALTER TABLE ... COALESCE PARTITION . Например, предположите, что Вы имеете таблицу, содержащую данные относительно клиентуры, которая разделена на двенадцать разделов. Таблица clients определена как показано здесь:

    CREATE TABLE clients (id INT, fname VARCHAR(30),
                          lname VARCHAR(30), signed DATE)
           PARTITION BY HASH(MONTH(signed)) PARTITIONS 12;
    

    Чтобы уменьшить число разделов с двенадцати до восьми, выполните следующую команду ALTER TABLE:

    mysql> ALTER TABLE clients COALESCE PARTITION 4;
    Query OK, 0 rows affected (0.02 sec)
    

    COALESCE работает одинаково хорошо с таблицами, которые разбиты на разделы HASH, KEY, LINEAR HASH или LINEAR KEY. Имеется пример, подобный предыдущему, отличаясь только тем, что таблица разбита на разделы LINEAR KEY:

    mysql> CREATE TABLE clients_lk (id INT, fname VARCHAR(30),
        ->                          lname VARCHAR(30), signed DATE)
        ->        PARTITION BY LINEAR KEY(signed) PARTITIONS 12;
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> ALTER TABLE clients_lk COALESCE PARTITION 4;
    Query OK, 0 rows affected (0.06 sec)
    Records: 0 Duplicates: 0 Warnings: 0
    

    Обратите внимание, что число, следующее за COALESCE PARTITION являются числом разделов, которое надлежит удалить из таблицы.

    Если Вы пытаетесь удалить большее количество разделов, чем таблица имеет, результатом будет ошибка:

    mysql> ALTER TABLE clients COALESCE PARTITION 18;
    ERROR 1478 (HY000): Cannot remove all partitions, use DROP TABLE instead
    

    Чтобы увеличить число разделов для таблицы clients с 12 до 18, скомандуйте ALTER TABLE ... ADD PARTITION:

    ALTER TABLE clients ADD PARTITION PARTITIONS 6;
    

    3.3.3. Сопровождение разделов

    Ряд задач сопровождения выделения разделов может быть выполнен в MySQL 5.1. MySQL не поддерживает команды CHECK TABLE, OPTIMIZE TABLE, ANALYZE TABLE или REPAIR TABLE для разбитых на разделы таблиц. Вместо этого Вы можете использовать ряд расширений ALTER TABLE, которые были выполнены в MySQL 5.1.5. Они могут использоваться для выполнения операций этого типа на одном или большем количестве разделов непосредственно, как описано в следующем списке:

    • Rebuilding partitions : восстанавливает раздел: это имеет тот же самый эффект, что и удаление всех записей, сохраненных в разделе, с последующей перевставкой их. Это может быть полезно с целью дефрагментации. Пример:

      ALTER TABLE t1 REBUILD PARTITION p0, p1;
      
    • Optimizing partitions: если Вы удалили большое количество строк из раздела или сделали много изменений для разбитой на разделы таблицы со строками переменной длины (то есть, имея столбцы VARCHAR, BLOB или TEXT), Вы можете использовать ALTER TABLE ... OPTIMIZE PARTITION, чтобы восстановить неиспользуемое место и дефрагментировать файл данных раздела:

      ALTER TABLE t1 OPTIMIZE PARTITION p0, p1;
      

      Использование OPTIMIZE PARTITION на данном разделе эквивалентно выполнению CHECK PARTITION, ANALYZE PARTITION и REPAIR PARTITION.

    • Analyzing partitions: читает и сохраняет распределения ключа для разделов. Пример:

      ALTER TABLE t1 ANALYZE PARTITION p3;
      
    • Repairing partitions: это восстанавливает разрушенные разделы. Пример:

      ALTER TABLE t1 REPAIR PARTITION p0,p1;
      
    • Checking partitions: Вы можете проверять раздел на ошибки способом, которым Вы можете использовать CHECK TABLE с не разбитыми на разделы таблицами:

      ALTER TABLE trb3 CHECK PARTITION p1;
      

      Эта команда сообщит Вам, если данные или индексы в разделе p1 таблицы t1 разрушены. Если дело обстоит так, используйте ALTER TABLE ... REPAIR PARTITION для ремонта раздела.

    Вы можете также использовать утилиту mysqlcheck или myisamchk, чтобы выполнить эти задачи, действуя на отдельных .MYI-файлах, сгенерированных, выделяя разделы таблицы.

    3.3.4. Получение информации относительно разделов

    Этот раздел обсуждает получение информации относительно существующих разделов, что может быть выполнено несколькими способами. Они включают:

    • Использование инструкции SHOW CREATE TABLE, чтобы просмотреть предложения выделения разделов, используемые в создании разбитой на разделы таблицы.

    • Использование инструкции SHOW TABLE STATUS, чтобы определить, разбита ли таблица на разделы вообще.

    • Запрос таблицы INFORMATION_SCHEMA.PARTITIONS.

    • Использование инструкции EXPLAIN PARTITIONS SELECT, чтобы видеть, которые разделы используются данным SELECT.

    SHOW CREATE TABLE включает в вывод предложение PARTITION BY, используемое, чтобы создать разбитую на разделы таблицу. Например:

    mysql> SHOW CREATE TABLE trb3\G
    *************************** 1. row ***************************
    Table: trb3
    Create Table: CREATE TABLE `trb3` (`id` int(11) default NULL,
                                       `name` varchar(50) default NULL,
                                       `purchased` date default NULL)
                                       ENGINE=MyISAM DEFAULT CHARSET=latin1
    PARTITION BY RANGE (YEAR(purchased)) (
    PARTITION p0 VALUES LESS THAN (1990) ENGINE = MyISAM,
    PARTITION p1 VALUES LESS THAN (1995) ENGINE = MyISAM,
    PARTITION p2 VALUES LESS THAN (2000) ENGINE = MyISAM,
    PARTITION p3 VALUES LESS THAN (2005) ENGINE = MyISAM)
    1 row in set (0.00 sec)
    

    Обратите внимание: в ранних версиях MySQL 5.1 предложение PARTITIONS не показывалось для таблиц, разбитых на разделы HASH или KEY. Эта проблема была отфиксирована в MySQL 5.1.6.

    SHOW TABLE STATUS работает с разбитыми на разделы таблицами. Начиная с MySQL 5.1.9, вывод такой же, как для не разбитых на разделы таблиц за исключением того, что столбец Create_options содержит строку partitioned. В MySQL 5.1.8 и ранее столбец Engine всегда содержал значение PARTITION. Начиная с MySQL 5.1.9, этот столбец содержит имя типа памяти, используемого всеми разделами таблицы.

    Вы можете также получать информацию относительно разделов из INFORMATION_SCHEMA, которая содержит таблицу PARTITIONS.

    Начиная с MySQL 5.1.5, можно определить, которые разделы разбитой на разделы таблицы включаются в данном запросе SELECT, применяя EXPLAIN PARTITIONS. Ключевое слово PARTITIONS добавляет столбец partitions к выводу EXPLAIN, перечисляющего столбцы, из которых записи соответствуют запросу.

    Предположите, что Вы имеете таблицу trb1 определенную и заполняемую следующим образом:

    CREATE TABLE trb1 (id INT, name VARCHAR(50), purchased DATE)
           PARTITION BY RANGE(id) (PARTITION p0 VALUES LESS THAN (3),
                                   PARTITION p1 VALUES LESS THAN (7),
                                   PARTITION p2 VALUES LESS THAN (9),
                                   PARTITION p3 VALUES LESS THAN (11));
    INSERT INTO trb1 VALUES (1, 'desk organiser', '2003-10-15'),
                            (2, 'CD player', '1993-11-05'),
                            (3, 'TV set', '1996-03-10'),
                            (4, 'bookcase', '1982-01-10'),
                            (5, 'exercise bike', '2004-05-09'),
                            (6, 'sofa', '1987-06-05'),
                            (7, 'popcorn maker', '2001-11-22'),
                            (8, 'aquarium', '1992-08-04'),
                            (9, 'study desk', '1984-09-16'),
                            (10, 'lava lamp', '1998-12-25');
    

    Вы можете видеть, которые разделы используются в запросе типа SELECT * FROM trb1;, как показано здесь:

    mysql> EXPLAIN PARTITIONS SELECT * FROM trb1\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: trb1
    partitions: p0,p1,p2,p3
    type: ALL
    possible_keys: NULL
    key: NULL
    key_len: NULL
    ref: NULL
    rows: 10
    Extra: Using filesort
    

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

    mysql> EXPLAIN PARTITIONS SELECT * FROM trb1 WHERE id < 5\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: trb1
    partitions: p0, p1
    type: ALL
    possible_keys: NULL
    key: NULL
    key_len: NULL
    ref: NULL
    rows: 10
    Extra: Using where
    

    EXPLAIN PARTITIONS обеспечивают информацию относительно используемых и возможных ключей, точно как со стандартной инструкцией EXPLAIN SELECT:

    mysql> ALTER TABLE trb1 ADD PRIMARY KEY (id);
    Query OK, 10 rows affected (0.03 sec)
    Records: 10 Duplicates: 0 Warnings: 0
    
    mysql> EXPLAIN PARTITIONS SELECT * FROM trb1 WHERE id < 5\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: trb1
    partitions: p0, p1
    type: range
    possible_keys: PRIMARY
    key: PRIMARY
    key_len: 4
    ref: NULL
    rows: 7
    Extra: Using where
    

    Вы должны принять во внимание следующие ограничения на EXPLAIN PARTITIONS:

    • Вы не можете использовать ключевые слова PARTITIONS и EXTENDED вместе в том же самом запросе EXPLAIN ... SELECT. Попытка сделать так производит синтаксическую ошибку.

    • Если EXPLAIN PARTITIONS используется, чтобы исследовать запрос для не разбитой на разделы таблицы, никакая ошибка не будет произведена, но значение столбца partitions всегда NULL.

    3.4. Сокращение раздела

    Этот раздел обсуждает сокращение раздела (partition pruning), оптимизацию, которая была выполнена для разбитых на разделы таблиц в MySQL 5.1.6.

    Основное понятие сокращения раздела относительно просто, и может быть описано как "не просматриваются разделы, где не может иметься никаких значений соответствия". Например, предположите, что Вы имеете разбитую на разделы таблицу t1, определенную этой инструкцией:

    CREATE TABLE t1 (fname VARCHAR(50) NOT NULL, lname VARCHAR(50) NOT NULL,
                     region_code TINYINT UNSIGNED NOT NULL, dob DATE NOT NULL)
           PARTITION BY RANGE(region_code) (
                     PARTITION p0 VALUES LESS THAN (64),
                     PARTITION p1 VALUES LESS THAN (128),
                     PARTITION p2 VALUES LESS THAN (192)
                     PARTITION p3 VALUES LESS THAN MAXVALUE);
    

    Рассмотрите случай, где Вы желаете получить результат запроса типа этого:

    SELECT fname, lname, postcode, dob FROM t1
           WHERE region_code > 125 AND
           region_code < 130;
    

    Просто видеть, что ни одна из строк, которые должны быть возвращены, не будет в разделе p0 или p3. То есть, мы должны искать данные только в разделах p1 и p2, чтобы найти строки соответствий. Делая так, можно расходовать намного меньше времени и усилий в нахождении строк соответствий, чем при просмотре всех разделов в таблице. Это и известно как сокращение ( pruning). Когда оптимизатор может использовать сокращение раздела, выполнение запроса может быть на порядок быстрее, чем тот же самый запрос на не разбитой на разделы таблицы, содержащей те же самые определения столбца и данные.

    Оптимизатор запроса может выполнять сокращение всякий раз, когда условие WHERE может быть уменьшено до любого одного из следующего:

    • partition_column = constant

    • partition_column IN (constant1, constant2, ..., constantN)

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

    Сокращение может также применяться к коротким диапазонам, которые оптимизатор может преобразовывать в эквивалентные списки значений. Например, в предыдущем примере, предложение WHERE может быть преобразовано в WHERE region_code IN (125, 126, 127, 128, 129, 130). Затем оптимизатор может определять, что первые три значения в списке найдены в разделе p1, следующие три значения в разделе p2 и что другие разделы не содержат никаких релевантных значений.

    Этот тип оптимизации может применяться всякий раз, когда выражение выделения разделов состоит из равенства или диапазона, который может быть уменьшен до набора равенств, или же когда выражение выделения разделов представляет связь уменьшения или увеличение. Сокращение может также быть применено для таблиц, разбитых на разделы на основании столбцов DATE или DATETIME, когда выражение выделения разделов использует функцию YEAR() или TO_DAYS(). Обратите внимание: в будущих версиях MySQL планируется добавлять поддержку сокращения для дополнительных функций, которые действуют на значения DATE или DATETIME, возвращают целое число и увеличиваются или уменьшаются. Например, предположите, что таблица t2, определенная как показано здесь, разбита на разделы на столбце DATE:

    CREATE TABLE t2 (fname VARCHAR(50) NOT NULL, lname VARCHAR(50) NOT NULL,
                     region_code TINYINT UNSIGNED NOT NULL,
                     dob DATE NOT NULL)
           PARTITION BY RANGE(YEAR(dob)) (
                     PARTITION d0 VALUES LESS THAN (1970),
                     PARTITION d1 VALUES LESS THAN (1975),
                     PARTITION d2 VALUES LESS THAN (1980),
                     PARTITION d3 VALUES LESS THAN (1985),
                     PARTITION d4 VALUES LESS THAN (1990),
                     PARTITION d5 VALUES LESS THAN (2000),
                     PARTITION d6 VALUES LESS THAN (2005),
                     PARTITION d7 VALUES LESS THAN MAXVALUE);
    

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

    SELECT * FROM t2 WHERE dob = '1982-06-23';
    SELECT * FROM t2 WHERE dob BETWEEN '1991-02-15' AND '1997-04-25';
    SELECT * FROM t2 WHERE YEAR(dob) IN (1979, 1980, 1983, 1985, 1986, 1988);
    SELECT * FROM t2 WHERE dob >= '1984-06-21' AND dob <= '1999-06-21'
    

    В случае последнего запроса оптимизатор может также действовать следующим образом:

    1. Найти раздел, содержащий нижний конец диапазона..

      YEAR('1984-06-21') выдает значение 1984, которое найдено в разделе d3.

    2. Найти раздел, содержащий верхний конец диапазона..

      YEAR('1999-06-21') оценивается к 1999, которое найдено в разделе d5.

    3. Просмотреть только эти два раздела и любые разделы, которые могут находиться между ними.

      В этом случае, это означает, что просмотрены только разделы d3, d4 и d5. Остающиеся разделы могут безопасно игнорироваться (и игнорируются).

    Пока мы смотрели только на примеры, использующие выделение разделов RANGE, но сокращение может применяться также и с другими типами выделения разделов.

    Рассмотрите таблицу, которая разбита на разделы LIST, где выражение выделения разделов увеличивается или уменьшается, типа таблицы t3, показанной здесь. В этом примере мы принимаем для краткости, что столбец region_code ограничен значениями от 1 до 10.

    CREATE TABLE t3 (fname VARCHAR(50) NOT NULL, lname VARCHAR(50) NOT NULL,
                     region_code TINYINT UNSIGNED NOT NULL,
                     dob DATE NOT NULL)
           PARTITION BY LIST(region_code) (
                        PARTITION r0 VALUES IN (1, 3),
                        PARTITION r1 VALUES IN (2, 5, 8),
                        PARTITION r2 VALUES IN (4, 9),
                        PARTITION r3 VALUES IN (6, 7, 10));
    

    Для запроса типа SELECT * FROM t3 WHERE region_code BETWEEN 1 AND 3 оптимизатор определяет, в которых разделах значения 1, 2 и 3 найдены (r0 и r1) и пропускает остающиеся (r2 и r3).

    Для таблиц, которые разбиты на разделы HASH или KEY, сокращение раздела также возможно в случаях, в которых предложение WHERE использует простое отношение = против столбца, используемого в выражении выделения разделов. Рассмотрите таблицу, созданную подобно этому:

    CREATE TABLE t4 (fname VARCHAR(50) NOT NULL, lname VARCHAR(50) NOT NULL,
                     region_code TINYINT UNSIGNED NOT NULL,
                     dob DATE NOT NULL)
           PARTITION BY KEY(region_code) PARTITIONS 8;
    

    Любой запрос типа этого может быть сокращен:

    SELECT * FROM t4 WHERE region_code = 7;
    

    Сокращение также может быть использовано для коротких диапазонов, потому что оптимизатор может направлять такие условия в отношениях IN. Например, при использовании той же самой таблицы t4 как определено ранее, запросы типа этих могут быть сокращены:

    SELECT * FROM t4 WHERE region_code > 2 AND region_code < 6;
    SELECT * FROM t4 WHERE region_code BETWEEN 3 AND 5;
    

    В обеих случаях, предложения WHERE преобразованы оптимизатором в WHERE region_code IN (3, 4, 5). Важно: эта оптимизация используется только, если размер диапазона меньший, чем число разделов. Рассмотрите этот запрос:

    SELECT * FROM t4 WHERE region_code BETWEEN 4 AND 8;
    

    Диапазон в предложении WHERE покрывает 5 значений (4, 5, 6, 7, 8), но t4 имеет только 4 раздела. Это означает, что предыдущий запрос никак не может быть сокращен.

    Сокращение может использоваться только на целочисленных столбцах таблиц, разбитых на разделы HASH или KEY. Например, этот запрос на таблице t4 не может использовать сокращение, потому что dob столбец типа DATE:

    SELECT * FROM t4 WHERE dob >=- '2001-04-14' AND dob <= '2005-10-15';
    

    Однако, если таблица сохраняет значения года в столбце типа INT, то запрос WHERE year_col >= 2001 AND year_col <= 2005 может быть сокращен.

    3.5. Ограничения выделения разделов

    Этот раздел обсуждает текущие ограничения поддержки выделения разделов MySQL:

    • Начиная с MySQL 5.1.12, следующие конструкции не разрешаются в выражениях выделения разделов:

      • Вложенные обращения к функциям (то есть, конструкции типа func1(func2( col_name))).

      • Сохраненные процедуры, функции, UDF или plugins.

      • Объявленные переменные или переменные пользователя.

    • Начиная с MySQL 5.1.12, следующие функции MySQL специально не позволяются в выражениях выделения разделов:

      • GREATEST()

      • ISNULL()

      • LEAST()

      • CASE()

      • IFNULL()

      • NULLIF()

      • BIT_LENGTH()

      • CHAR_LENGTH()

      • CHARACTER_LENGTH()

      • FIND_IN_SET()

      • INSTR()

      • LENGTH()

      • LOCATE()

      • OCTET_LENGTH()

      • POSITION()

      • STRCMP()

      • CRC32()

      • ROUND()

      • SIGN()

      • DATEDIFF()

      • PERIOD_ADD()

      • PERIOD_DIFF()

      • TIMESTAMPDIFF()

      • UNIX_TIMESTAMP()

      • WEEK()

      • CAST()

      • CONVERT()

      • BIT_COUNT()

      • INET_ATON()

    • Использование арифметических операторов +, -, * и / разрешается в выражениях выделения разделов. Однако, результат должен быть целочисленным значением или NULL (за исключением [LINEAR] KEY).

      Начиная с MySQL 5.1.12, разрядные операторы |, &, ^, <<, >> и ~ не разрешаются в выражениях выделения разделов.

    • Начиная с MySQL 5.1.12, только следующие функции MySQL поддерживаются в выражениях выделения разделов:

      • ABS()

      • ASCII()

      • CEILING()

      • DAY()

      • DAYOFMONTH()

      • DAYOFWEEK()

      • DAYOFYEAR()

      • EXTRACT()

      • FLOOR()

      • HOUR()

      • MICROSECOND()

      • MINUTE()

      • MOD()

      • MONTH()

      • ORD()

      • QUARTER()

      • SECOND()

      • TIME_TO_SEC()

      • TO_DAYS()

      • WEEKDAY()

      • WEEKOFYEAR()

      • YEAR()

      • YEARWEEK()

    • Важно: Вы должны иметь в виду, что результаты многих функций MySQL и операторов могут изменять SQL-режим сервера. По этой причине нежелательно изменять этот режим после создания разбитых на разделы таблиц.

    • Использование функций ASCII() или ORD(), чтобы преобразовать строковое значение (столбца типа CHAR или VARCHAR) к целому числу работает только, когда строка использует 8-разрядный набор символов. Объединение, используемое для строки, может быть любым объединением для связанного набора символов. Однако, объединения latin1_german2_ci, latin2_czech_cs и cp1250_czech_cs не могут использоваться, вследствие того, что эти объединения требуют символьных преобразований "один ко многим".

    • Если при создании таблиц с очень большим количеством разделов Вы сталкиваетесь с сообщением об ошибках типа Got error 24 from storage engine, Вы должны увеличить значение переменной системы open_files_limit.

    • Разбитые на разделы таблицы не поддерживают внешние ключи. Это включает разбитые на разделы таблицы, использующие тип памяти InnoDB.

    • Разбитые на разделы таблицы не поддерживают индексы FULLTEXT. Это включает разбитые на разделы таблицы, использующие тип памяти MyISAM.

    • Разбитые на разделы таблицы не поддерживают столбцы GEOMETRY.

    • Начиная с MySQL 5.1.8, временные таблицы не могут быть разбиты на разделы (Глюк #17497 ).

    • Таблицы, использующие тип памяти MERGE, не могут быть разбиты на разделы.

      Разбитые на разделы таблицы, использующие тип памяти CSV, не обеспечиваются. Начиная с MySQL 5.1.12, невозможно создать разбитые на разделы таблицы CSV вообще.

      До MySQL 5.1.6 таблицы, использующие тип памяти BLACKHOLE, также не могли быть разбиты на разделы.

      Выделение разделов KEY (или LINEAR KEY) представляет собой единственный тип выделения разделов обеспечиваемого для типа памяти NDB. Начиная с MySQL 5.1.12, невозможно создать таблицу Cluster, использующую любое выделение разделов, кроме [LINEAR ] KEY, а попытка это сделать вызывает ошибку.

    • При выполнении обновления, таблицы, использующие любой тип памяти (кроме NDBCLUSTER), которые разбиты на разделы KEY, должны разгрузиться и перезагрузиться.

    • Все разделы таблицы и подразделы (если имеется любой из последних) должны использовать тот же самый тип памяти.

    • Ключ выделения разделов должен быть целочисленным столбцом или выражением, которое решается к целому числу. Столбец или значение выражения может также быть NULL.

      Одна исключительная ситуация к этому ограничению происходит при выделении разделов [LINEAR] KEY, где возможно использовать столбцы других типов как ключи выделения разделов потому, что MySQL с помощью хэш-функции производит внутренний ключ правильного типа данных из этих типов. Например, следующая инструкция CREATE TABLE допустима:

      CREATE TABLE tkc (c1 CHAR) PARTITION BY KEY(c1) PARTITIONS 4;
      

      Эта исключительная ситуация не относится к типам столбцов BLOB или TEXT.

    • Ключ выделения разделов не может быть подзапросом, даже если этот подзапрос решается к целочисленному значению или NULL.

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

      CREATE TABLE t1 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       UNIQUE KEY (col1, col2))
             PARTITION BY HASH(col3) PARTITIONS 4;
      CREATE TABLE t2 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       UNIQUE KEY (col1), UNIQUE KEY (col3))
             PARTITION BY HASH(col1 + col3) PARTITIONS 4;
      CREATE TABLE t3 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       UNIQUE KEY (col1, col2), UNIQUE KEY (col3))
             PARTITION BY HASH(col1 + col3) PARTITIONS 4;
      

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

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

      CREATE TABLE t1 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       UNIQUE KEY (col1, col2, col3))
             PARTITION BY HASH(col3) PARTITIONS 4;
      CREATE TABLE t2 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       UNIQUE KEY (col1, col3))
             PARTITION BY HASH(col1 + col3) PARTITIONS 4;
      CREATE TABLE t3 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       UNIQUE KEY (col1, col2, col3), UNIQUE KEY (col3))
             PARTITION BY HASH(col3) PARTITIONS 4;
      

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

      CREATE TABLE t4 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       PRIMARY KEY(col1, col2))
             PARTITION BY HASH(col3) PARTITIONS 4;
      CREATE TABLE t5 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       PRIMARY KEY(col1, col3), UNIQUE KEY(col2))
             PARTITION BY HASH(YEAR(col2)) PARTITIONS 4;
      

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

      CREATE TABLE t6 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       PRIMARY KEY(col1, col2))
             PARTITION BY HASH(col1 + YEAR(col2)) PARTITIONS 4;
      CREATE TABLE t7 (col1 INT NOT NULL, col2 DATE NOT NULL,
                       col3 INT NOT NULL, col4 INT NOT NULL,
                       PRIMARY KEY(col1, col2, col4), UNIQUE KEY(col2, col1))
             PARTITION BY HASH(col1 + YEAR(col2)) PARTITIONS 4;
      

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

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

      CREATE TABLE t_no_pk (c1 INT, c2 INT)
             PARTITION BY RANGE(c1) (PARTITION p0 VALUES LESS THAN (10),
                       PARTITION p1 VALUES LESS THAN (20),
                       PARTITION p2 VALUES LESS THAN (30),
                       PARTITION p3 VALUES LESS THAN (40));
      

      Возможно добавить первичный ключ к t_no_pk, используя любую из этих инструкций ALTER TABLE:

      # possible PK
      ALTER TABLE t_no_pk ADD PRIMARY KEY(c1);
      # also a possible PK
      ALTER TABLE t_no_pk ADD PRIMARY KEY(c1, c2);
      

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

      # fails with ERROR 1482
      ALTER TABLE t_no_pk ADD PRIMARY KEY(c2);
      

      С тех пор как t_no_pk имеет только c1 в выражении выделения разделов, попытка добавления уникального ключа на c2 всегда провалится. Однако, Вы можете добавлять уникальный ключ, который использует c1 и c2.

      Эти правила также относятся к существующим не разбитым на разделы таблицам, в которых Вы желаете выделить разделы используя ALTER TABLE ... PARTITION BY. Рассмотрите таблицу np_pk:

      CREATE TABLE np_pk (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50),
                          added DATE, PRIMARY KEY (id));
      

      Следующяя инструкция ALTER TABLE потерпит неудачу с ошибкой, потому что столбец added не является частью любого уникального ключа в таблице:

      ALTER TABLE np_pk PARTITION BY HASH(TO_DAYS(added)) PARTITIONS 4;
      

      Эта инструкция, однако, была бы полностью допустима:

      ALTER TABLE np_pk PARTITION BY HASH(id) PARTITIONS 4;
      

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

    • Подразделы ограничены выделением разделов HASH или KEY. Разделы HASH и KEY не могут быть подразбиты на разделы.

    de>YEARWEEK()

  • Важно: Вы должны иметь в виду, что результаты многих функций Mmysqlpro/restrict.htm 600 0 0 54326 10643273020 10303 Глава 11. Ограничения свойств

    Глава 11. Ограничения свойств

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

    11.1. Ограничения на сохраненные подпрограммы и триггеры

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

    Сохраненные подпрограммы не могут содержать произвольные инструкции SQL. Следующие инструкции отвергнуты:

    • Инструкции блокировки LOCK TABLES и UNLOCK TABLES.

    • LOAD DATA и LOAD TABLE.

    • Подготовленные инструкции SQL (PREPARE, EXECUTE, DEALLOCATE PREPARE). Вы не можете использовать динамический SQL внутри сохраненных подпрограмм (где Вы создаете динамически инструкции как строки, а затем выполняете их). Это ограничение снимается в MySQL 5.0.13 для сохраненных процедур, но это все еще применяется к сохраненным функциям и триггерам.

    Для сохраненных функций (но не для процедур) следующие дополнительные инструкции или операции отвергнуты:

    • Инструкции, которые делают явный или неявный commit или rollback.

    • Инструкции, которые возвращают набор результатов. Это включает инструкции SELECT, которые не имеют предложения INTO var_list, и инструкции SHOW. Функция может обрабатывать набор результатов через SELECT ... INTO var_list или используя курсор и инструкции FETCH.

    • Все инструкции FLUSH.

    • Инструкции рекурсии. То есть, сохраненные функции не могут использоваться рекурсивно.

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

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

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

    CREATE PROCEDURE p (i INT)
    BEGIN
      DECLARE i INT DEFAULT 0;
      SELECT i FROM t;
      BEGIN
        DECLARE i INT DEFAULT 1;
        SELECT i FROM t;
      END;
    END;
    

    В таких случаях идентификатор неоднозначен, и следующие правила старшинства применяются:

    • Локальная переменная имеет приоритет над стандартным параметром или столбцом таблицы.

    • Стандартный параметр имеет приоритет над столбцом таблицы.

    • Локальная переменная во внутреннем блоке имеет приоритет над локальной переменной во внешнем блоке.

    Поведение, что столбцы таблицы не имеют приоритет над переменными, ненормативно.

    Использование сохраненных подпрограмм может вызывать проблемы дублирования. Эта проблема рассмотрена далее.

    INFORMATION_SCHEMA еще не имеет таблицу PARAMETERS, так что прикладные программы, которым надо собирать стандартную информацию параметров во время выполнения должны использовать методы типа синтаксического анализа вывода инструкций SHOW CREATE.

    Не имеется никакой системы отладки сохраненных подпрограмм.

    Инструкции CALL не могут быть подготовлены.

    Драйверы UNDO не обеспечиваются.

    Циклы FOR не обеспечиваются.

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

    Инструкция RENAME DATABASE не перемещает сохраненные подпрограммы к новому имени схемы.

    Для триггеров следующие дополнительные инструкции или операции отвергнуты:

    • Триггеры в настоящее время не активизированы действиями внешнего ключа.

    • Инструкция RETURN запрещена в триггере, который не может возвращать значение. Чтобы выходить из него немедленно, используйте инструкцию LEAVE.

    • Триггеры не позволяются на таблицах в базе данных mysql.

    11.2. Ограничения на курсоры сервера

    Курсоры стороны сервера выполнены в C API через функцию mysql_stmt_attr_set(). Та же самая реализация используется для курсоров в сохраненных подпрограммах. Курсор стороны сервера позволяет набору результатов быть сгенерированным на стороне сервера, но не перемещен пользователю, кроме тех строк, которые пользователь запрашивает. Например, если пользователь выполняет запрос, но заинтересован только первой строкой, остающиеся строки не будут перемещены.

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

    Курсоры предназначены пока только для чтения: Вы не можете использовать курсор, чтобы модифицировать строки. А поэтому обновляемые курсоры не обеспечиваются. Следовательно, UPDATE WHERE CURRENT OF и DELETE WHERE CURRENT OF не выполнены.

    Курсоры не сохраняются открытыми после передачи.

    Курсоры не прокручиваемые.

    Курсоры не именованы. Операторный драйвер действует как курсор ID.

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

    Вы не можете использовать курсор для инструкции, которая генерирует набор результатов, если инструкция не обеспечивается в подготовленном режиме. Это включает инструкции типа CHECK TABLES, HANDLER READ и SHOW BINLOG EVENTS.

    11.3. Ограничения на подзапросы

    • Известная ошибка, которая будет фиксирована позже: если Вы сравниваете значение NULL с подзапросом, использующим ALL, ANY или SOME, и подзапрос возвращают пустой результат, сравнение может быть оценено к ненормативному результату NULL, а не к TRUE или FALSE.

    • Внешняя инструкция подзапроса может быть любой из SELECT, INSERT, UPDATE, DELETE, SET или DO.

    • Оптимизация подзапроса для IN не как эффективна, как для оператора = или для конструкции IN(value_list).

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

      Проблема состоит в том, что для инструкции, которая использует в подзапросе IN, оптимизатор перезаписывает это как соотнесенный подзапрос. Рассмотрите следующую инструкцию, которая использует несоотнесенный подзапрос:

      SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);
      

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

      SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);
      

      Если внутренние и внешние запросы возвращают M и N строк соответственно, время выполнения становится порядка O(M^N), а не O(M+N), как это было бы для несоотнесенного подзапроса.

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

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

      DELETE FROM t WHERE ... (SELECT ... FROM t ...);
      UPDATE t ... WHERE col = (SELECT ... FROM t ...);
      {INSERT|REPLACE} INTO t (SELECT ... FROM t ...);
      

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

      UPDATE t ... WHERE col = (SELECT (SELECT ... FROM t...) AS _t ...);
      

      Здесь запрещение не применяется, потому что результат от подзапроса в предложении FROM сохранен как временная таблица, так что релевантные строки в t уже были выбраны ко времени модификации t.

    • Операции сравнения строк обеспечиваются пока только частично:

      • Для expr IN (subquery), expr может быть n-кортеж (определенный через синтаксис конструктора строки) и подзапрос может возвращать строки n-кортежей.

      • Для expr op {ALL|ANY|SOME} (подзапрос), expr должен быть скалярным значением, и подзапрос должен быть подзапросом столбца, это не может возвращать строки с многими столбцами.

      Другими словами, для подзапроса, который возвращает строки n-кортежей, это обеспечивается:

      (val_1, ..., val_n) IN
      (subquery)
      

      Но это не обеспечивается:

      (val_1, ..., val_n)
      op {ALL|ANY|SOME} (subquery)
      

      Причина для обеспечения сравнений строки для IN, но не для других: IN выполнен, перезаписывая это как последовательность сравнений = и операций AND. Этот подход не может использоваться для ALL, ANY или SOME.

    • Конструкторы строк не оптимизированы хорошо. Следующие два выражения эквивалентны, но только второе может быть оптимизировано:

      (col1, col2, ...) = (val1, val2, ...)
      col1 = val1 AND col2 = val2 AND ...
      
    • Подзапросы в предложении FROM не могут быть соотнесены подзапросам. Они осуществлены (выполнены, чтобы произвести набор результатов) перед оценкой внешнего запроса, так что они не могут быть оценены на строку внешнего запроса.

    • Оптимизатор более отлажен для объединений, чем для подзапросов, так что во многих случаях инструкция, применяющая подзапрос, может быть выполнена более эффективно, если Вы переписываете это как объединение.

      Исключительная ситуация происходит для случая, где подзапрос IN может быть переписан как объединение SELECT DISTINCT. Пример:

      SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE
             condition);
      

      Эта инструкция может быть переписана следующим образом:

      SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND
             condition;
      

      Но в этом случае объединение требует операции DISTINCT, и не более эффективно, чем подзапрос.

    • Возможная будущая оптимизация: MySQL не переписывает порядок объединения для оценки подзапроса. В некоторых случаях подзапрос мог бы быть выполнен более эффективно, если MySQL переписал это как объединение. Это дало бы оптимизатору возможность, чтобы выбрать между большим количеством планов выполнения. Например, это могло бы решать, читать ли одну таблицу или другую первой:

      SELECT a FROM outer_table AS ot
             WHERE a IN (SELECT a FROM inner_table AS
             it WHERE ot.b = it.b);
      

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

      Предшествующий запрос мог бы быть переписан подобно этому:

      SELECT a FROM outer_table AS ot, inner_table AS it
             WHERE ot.a = it.a AND
             ot.b = it.b;
      

      В этом случае мы можем просматривать маленькую таблицу (inner_table) и искать строки в outer_table, что будет быстро, если имеется индекс на (ot.a,ot.b).

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

    • Возможная будущая оптимизация: подзапрос в предложении FROM оценен, осуществляя результат во временную таблицу, и эта таблица не использует индексы. Это не позволяет использование индексов по сравнению с другими таблицами в запросе, хотя это могло бы быть полезно.

    • Возможная будущая оптимизация: если подзапрос в предложении FROM походит на просмотр, к которому может применяться объединяющийся алгоритм, переписать запрос и применить объединяющийся алгоритм так, чтобы индексы могли использоваться. Следующая инструкция содержит такой подзапрос:

      SELECT * FROM (SELECT * FROM t1 WHERE t1.t1_col) AS _t1, t2 WHERE t2.t2_col;
      

      Инструкция может быть переписана как объединение подобно этому:

      SELECT * FROM t1, t2 WHERE t1.t1_col AND t2.t2_col;
      

      Этот тип перезаписи обеспечил бы две выгоды:

      • Это избегает использования временной таблицы, для которой никакие индексы не могут использоваться. В переписанном запросе оптимизатор может использовать индексы на t1.

      • Это дает оптимизатору большее количество свободы выбрать между различными планами выполнения. Например, перезапись запроса как объединения позволяет оптимизатору использовать сначала t1 или t2.

    • Возможная будущая оптимизация: для IN, = ANY, <> ANY, = ALL и <> ALL с не соотнесенными подзапросами использовать в оперативной памяти хэш для результата или временную таблицу с индексом для больших результатов. Пример:

      SELECT a FROM big_table AS bt WHERE non_key_field IN
             (SELECT non_key_field FROM table WHERE
             condition)
      

      В этом случае мы могли бы создавать временную таблицу:

      CREATE TABLE t (key (non_key_field))
             (SELECT non_key_field FROM table WHERE
             condition)
      

      Затем для каждой строки в big_table сделайте поисковую таблицу ключа в t, основываясь на bt.non_key_field.

    11.4. Ограничения на Views

    Обработка View не оптимизирована:

    • Невозможно создать индекс на view.

    • Индексы могут использоваться для обработанных view, используя объединяющий алгоритм. Однако, view, который обработан алгоритмом temptable, не способен пользоваться преимуществом индексов на основных таблицах (хотя индексы могут использоваться в течение поколения временных таблиц).

    Подзапросы не могут использоваться в предложении FROM view. Это ограничение будет сниматься в будущем.

    Имеется общий принцип, что Вы не можете изменять таблицу и выбирать из той же самой таблицы в подзапросе.

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

    CREATE VIEW v1 AS SELECT * FROM t2 WHERE EXISTS (SELECT 1 FROM t1 WHERE
           t1.a = t2.a);
    UPDATE t1, v2 SET t1.a = 1 WHERE t1.b = v2.b;
    

    Если view оценен, используя временную таблицу, Вы можете выбирать из таблицы в view подзапросом и менятт ту таблицу во внешнем запросе. В этом случае view будет сохранен во временной таблице, и таким образом Вы действительно не выбираете из таблицы в подзапросе и изменяете таблицу в то же самое время. Можно принудительно предписать MySQL использовать алгоритм temptable, определяя ALGORITHM = TEMPTABLE в определении view.

    Вы можете использовать DROP TABLE или ALTER TABLE, чтобы удалять или изменять таблицу, которая используется в определении view (это объявляет неверным view), и никакого предупреждения не последует. Ошибка происходит позже, когда view используется.

    Определение view заморожено некоторыми инструкциями:

    • Если инструкция, подготовленная PREPARE, обращается к view, то содержание этого view какждый раз при выполнении инструкции будет точно соответствовать моменту ее подготовки. Это истинно, даже если определение view изменен после того, как инструкция подготовлена, но прежде, чем она выполнена. Пример:

      CREATE VIEW v AS SELECT 1;
      PREPARE s FROM 'SELECT * FROM v';
      ALTER VIEW v AS SELECT 2;
      EXECUTE s;
      

      Результат, возвращенный инструкцией EXECUTE, 1, а не 2.

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

      CREATE VIEW v AS SELECT 1;
      delimiter //
      CREATE PROCEDURE p ()
      BEGIN
        DECLARE i INT DEFAULT 0;
        WHILE i < 5 DO
          SELECT * FROM v;
          SET i = i + 1;
          ALTER VIEW v AS SELECT 2;
        END WHILE;
      END;
      //
      delimiter ;
      CALL p();
      

      Когда процедура p() вызвана, SELECT возвращает 1 каждый раз в цикле, даже при том, что определение view изменено внутри цикла.

    Относительно обновляемых view: полная цель для view состоит в том, что, если любой view является теоретически обновляемым, это должно быть обновляемым и практически. Это включает view, которые имеют UNION в их определении. В настоящее время не все просмотры, которые являются теоретически обновляемыми, таковы на деле (могут модифицироваться). Начальная реализация view была преднамеренно написана этим способом, чтобы стать пригодной для использования, обновляемые view в MySQL будут сделаны настолько быстро, насколько возможно. Многие теоретически обновляемые view могут модифицироваться теперь, но ограничения все еще существуют:

    • Обновляемые view с подзапросами где-нибудь не в предложении WHERE. Некоторые view, которые имеют подзапросы в списке SELECT, могут быть обновляемыми.

    • Вы не можете использовать UPDATE, чтобы модифицировать больше, чем одну основную таблицу view, который определен как объединение.

    • Вы не можете использовать DELETE, чтобы модифицировать view, который определен как объединение.

    Если пользователю предоставляют базисные привилегии, необходимые, чтобы создавать view (привилегии CREATE VIEW и SELECT), этот пользователь будут не способен вызвать SHOW CREATE VIEW на этом объекте, если пользователю не предоставляют также привилегию SHOW VIEW.

    Этот недостаток может привести к проблемам при копировании базы данных с помощью mysqldump, которая может терпеть неудачу из-за недостаточных привилегий. Эта проблема описана в Глюке #22062.

    Обход: чтобы администратор вручную предоставил привилегию SHOW VIEW пользователям, которым предоставляется CREATE VIEW, так как MySQL не предоставляет это неявно, когда создан view.

    11.5. Ограничения на Join

    Максимальное число таблиц, которые могут быть названы в одиночном объединении, составляет 61. Это также применяется к числу таблиц, которые могут быть названы в определении view.

    проса, так что они не могут быть оценены на строку внешнего запроса.

  • Оптимизатор более отлажен для объединений, чем для подзапросов, так что во многих случаях инструкция, применяющая подзапрос, может быть выполнена более эффективно, если Вы переписываете это как объединение. Глава 9. База данных <code>INFORMATION_SCHEMA</code>

    Глава 9. База данных INFORMATION_SCHEMA

    INFORMATION_SCHEMA обеспечивает доступ к метаданным базы данных.

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

    INFORMATION_SCHEMA информационная база данных, место, которое сохраняет информацию относительно всех других баз данных, которые поддерживает сервер MySQL. Внутри INFORMATION_SCHEMA имеется несколько таблиц только для чтения. Они фактически view, а не обычные таблицы, так как не имеется никаких файлов, связанных с ними.

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

    Имеется пример инструкции, которая получает информацию из INFORMATION_SCHEMA:

    mysql> SELECT table_name, table_type, engine
        ->        FROM information_schema.tables
        ->        WHERE table_schema = 'db5' ORDER BY table_name DESC;
    +------------+------------+--------+
    | table_name | table_type | engine |
    +------------+------------+--------+
    |        v56 | VIEW       | NULL   |
    |         v3 | VIEW       | NULL   |
    |         v2 | VIEW       | NULL   |
    |          v | VIEW       | NULL   |
    |     tables | BASE TABLE | MyISAM |
    |         t7 | BASE TABLE | MyISAM |
    |         t3 | BASE TABLE | MyISAM |
    |         t2 | BASE TABLE | MyISAM |
    |          t | BASE TABLE | MyISAM |
    |         pk | BASE TABLE | InnoDB |
    |       loop | BASE TABLE | MyISAM |
    |       kurs | BASE TABLE | MyISAM |
    |          k | BASE TABLE | MyISAM |
    |       into | BASE TABLE | MyISAM |
    |       goto | BASE TABLE | MyISAM |
    |        fk2 | BASE TABLE | InnoDB |
    |         fk | BASE TABLE | InnoDB |
    +------------+------------+--------+
    17 rows in set (0.01 sec)
    

    Объяснение: инструкция запрашивает список всех таблиц в базе данных db5 в обратном алфавитном порядке, показывая только три части информации: имя таблицы, тип таблицы и тип памяти.

    Каждый пользователь MySQL имеет право обратиться к этим таблицам, но может видеть только строки в таблицах, которые соответствуют объектам, для которых пользователь имеет соответствующие привилегии доступа. В некоторых случаях (например, столбец ROUTINE_DEFINITION в таблице INFORMATION_SCHEMA.ROUTINES), пользователи, которые имеют недостаточные привилегии, будут видеть NULL.

    Инструкция SELECT ... FROM INFORMATION_SCHEMA предназначена как более непротиворечивый способ обеспечить доступ к информации, обеспеченной различными инструкциями SHOW, которые MySQL поддерживает (SHOW DATABASES, SHOW TABLES и им подобные). Использование SELECT имеет эти преимущества перед SHOW:

    • Это соответствует правилам Кодда. То есть, весь доступ выполнен на таблицах.

    • Никто не должен узнавать новый операторный синтаксис. Потому что они уже знают, как работает SELECT, они должны узнать только объектные имена.

    • Реализаторы не должны волноваться относительно добавления ключевых слов.

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

    • Миграция проще, потому что каждая другая СУБД понимает этот способ.

    Однако, потому что команды SHOW популярна у пользователей MySQL, никто их убирать не собирается. Фактически, наряду с реализацией INFORMATION_SCHEMA, имеются расширения для SHOW.

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

    Реализация структур таблицы INFORMATION_SCHEMA в MySQL следует ANSI/ISO SQL:2003 Part 11 Schemata и в основном отвечает стандарту SQL:2003 core feature F021 Basic information schema.

    Пользователи SQL Server 2000 (который также следует стандарту) могут обратить внимание на сильное сходство. Однако, MySQL опустил много столбцов, которые нерелевантными для этой реализации, и добавил столбцы, которые являются MySQL-специфическими. Один такой столбец: ENGINE в таблице INFORMATION_SCHEMA.TABLES.

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

    • INFORMATION_SCHEMA Name указывает имя для столбца в таблице INFORMATION_SCHEMA. Это не соответствует стандартному имени SQL, если в поле Remarks значится MySQL extension.

    • SHOW Name указывает эквивалентное имя поля в самой близкой инструкции SHOW, если она имеется.

    • Remarks обеспечивает дополнительную информацию. Если это поле NULL, это означает, что значение столбца всегда NULL. Если это поле MySQL extension, столбец является расширением MySQL стандарта SQL.

    Чтобы избегать использовать любое имя, которое зарезервировано в стандарте SQL, DB2 или Oracle, имена некоторых столбцов, отмеченных как MySQL extension переделаны. Например, COLLATION на TABLE_COLLATION в таблице TABLES. Ссписок зарезервированных слов изложен в конце статьи на http://www.dbazine.com/gulutzan5.shtml.

    Определение для символьных столбцов (например, TABLES.TABLE_NAME) вообще VARCHAR(N) CHARACTER SET utf8, где N по крайней мере 64.

    Каждый раздел указывает то, какая инструкция SHOW является эквивалентной SELECT, который собирает информацию из INFORMATION_SCHEMA, если имеется такая инструкция.

    Обратите внимание: в настоящее время, имеются некоторые столбцы, расставленные не по порядку, а кое-какие еще вообще отсутствуют.

    9.1. Таблица INFORMATION_SCHEMA SCHEMATA

    Схема является базой данных, так что таблица SCHEMATA обеспечивает информацию относительно баз данных.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    CATALOG_NAME NULL
    SCHEMA_NAME База данных
    DEFAULT_CHARACTER_SET_NAME
    DEFAULT_COLLATION_NAME
    SQL_PATH NULL

    Следующие инструкции эквивалентны:

    SELECT SCHEMA_NAME AS `Database` FROM INFORMATION_SCHEMA.SCHEMATA
           [WHERE SCHEMA_NAME LIKE 'wild']
           SHOW DATABASES [LIKE 'wild']
    

    9.2. Таблица INFORMATION_SCHEMA TABLES

    Таблица TABLES обеспечивает информацию относительно таблиц в базах данных.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    TABLE_CATALOGNULL
    TABLE_SCHEMATable_...
    TABLE_NAMETable_ ...
    TABLE_TYPE
    ENGINEТип памяти MySQL extension
    VERSIONVersion MySQL extension
    ROW_FORMATRow_format MySQL extension
    TABLE_ROWSRows MySQL extension
    AVG_ROW_LENGTHAvg_row_length MySQL extension
    DATA_LENGTHData_length MySQL extension
    MAX_DATA_LENGTHMax_data_length MySQL extension
    INDEX_LENGTHIndex_length MySQL extension
    DATA_FREEData_free MySQL extension
    AUTO_INCREMENTAuto_increment MySQL extension
    CREATE_TIMECreate_time MySQL extension
    UPDATE_TIMEUpdate_time MySQL extension
    CHECK_TIMECheck_time MySQL extension
    TABLE_COLLATIONCollation MySQL extension
    CHECKSUMChecksum MySQL extension
    CREATE_OPTIONSCreate_options MySQL extension
    TABLE_COMMENTКомментарий MySQL extension

    Примечания:

    • TABLE_SCHEMA и TABLE_NAME одиночное поле в выводе SHOW, например: Table_in_db1.

    • TABLE_TYPE должен быть BASE TABLE или VIEW. Если таблица временная, то TABLE_TYPE = TEMPORARY. Не имеется никаких временных view, так что это однозначно.

    • Для разбитых на разделы таблиц, начиная с MySQL 5.1.9, столбец ENGINE показывает тип памяти, используемого всеми разделами. Раньше этот столбец показывал для таких таблиц PARTITION.

    • Столбец TABLE_ROWS NULL, если таблица находится в базе данных INFORMATION_SCHEMA. Для таблиц InnoDB счетчтк строк только грубая оценка, используемая в оптимизации SQL.

    • Для таблиц, использующих тип памяти NDBCLUSTER, начиная с MySQL 5.1.12, столбец DATA_LENGTH отражает истинное количество памяти для столбцов с переменной шириной. См. Глюк #18413.

      Обратите внимание: так как MySQL Cluster распределяет память для столбцов с переменной шириной в 10-страничных блоках по 32 килобайта каждый, использование места для таких столбцов сообщено в приращениях по 320 KB.

    • Мы не имеем ничего для заданного по умолчанию набора символов таблицы. TABLE_COLLATION близко, потому что имена объединения начинаются с имени набора символов.

    • Начиная с MySQL 5.1.9, столбец CREATE_OPTIONS показывается разбитый на разделы, если таблица разбита на разделы.

    Следующие инструкции эквивалентны:

    SELECT table_name FROM INFORMATION_SCHEMA.TABLES
           [WHERE table_schema = 'db_name']
           [WHERE|AND table_name LIKE 'wild']
           SHOW TABLES [FROM db_name]
           [LIKE 'wild']
    

    9.3. Таблица INFORMATION_SCHEMA COLUMNS

    Таблица COLUMNS обеспечивает информацию относительно столбцов в таблицах.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    TABLE_CATALOG NULL
    TABLE_SCHEMA
    TABLE_NAME
    COLUMN_NAMEПоле
    ORDINAL_POSITION См. примечания
    COLUMN_DEFAULTЗначение по умолчанию
    IS_NULLABLENull
    DATA_TYPEType
    CHARACTER_MAXIMUM_LENGTHType
    CHARACTER_OCTET_LENGTH
    NUMERIC_PRECISIONType
    NUMERIC_SCALEType
    CHARACTER_SET_NAME
    COLLATION_NAMECollation
    COLUMN_TYPEType MySQL extension
    COLUMN_KEYKey MySQL extension
    EXTRAExtra MySQL extension
    COLUMN_COMMENTComment MySQL extension

    Примечания:

    • В SHOW Type отображает включает значения из нескольких различных столбцов COLUMNS.

    • ORDINAL_POSITION необходим, потому что Вы могли бы указать ORDER BY ORDINAL_POSITION. В отличие от SHOW, SELECT не имеет автоматического упорядочения.

    • CHARACTER_OCTET_LENGTH должен быть таким же, как CHARACTER_MAXIMUM_LENGTH, если бы не многобайтовые наборы символов.

    • CHARACTER_SET_NAME может быть получен из Collation. Например, если Вы говорите SHOW FULL COLUMNS FROM t, и видите в столбце Collation значение latin1_swedish_ci, набор символов то, что перед первым символом подчеркивания: latin1.

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

    SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT
           FROM INFORMATION_SCHEMA.COLUMNS
           WHERE table_name = 'tbl_name'
           [AND table_schema = 'db_name']
           [AND column_name LIKE 'wild']
           SHOW COLUMNS FROM tbl_name
           [FROM db_name]
           [LIKE 'wild']
    

    9.4. Таблица INFORMATION_SCHEMA STATISTICS

    Таблица STATISTICS обеспечивает информацию относительно индексов таблицы.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    TABLE_CATALOGNULL
    TABLE_SCHEMA =база данных
    TABLE_NAMETable
    NON_UNIQUENon_unique
    INDEX_SCHEMA =база данных
    INDEX_NAMEKey_name
    SEQ_IN_INDEXSeq_in_index
    COLUMN_NAMEColumn_name
    COLLATIONCollation
    CARDINALITYCardinality
    SUB_PARTSub_part MySQL extension
    PACKEDPacked MySQL extension
    NULLABLENull MySQL extension
    INDEX_TYPEIndex_type MySQL extension
    COMMENTComment MySQL extension

    Примечания:

    • Не имеется никакой стандартной таблицы для индексов. Предшествующий список подобен тому, что возвращается SQL Server 2000 для sp_statistics, за исключением того, что заменили имя QUALIFIER на CATALOG и OWNER на SCHEMA.

      Предшествующая таблица и вывод из SHOW INDEX получен от того же самого родителя. Так что корреляция уже близкая.

    Следующие инструкции эквивалентны:

    SELECT * FROM INFORMATION_SCHEMA.STATISTICS
             WHERE table_name = 'tbl_name'
             [AND table_schema = 'db_name']
             SHOW INDEX FROM tbl_name
             [FROM db_name]
    

    9.5. Таблица INFORMATION_SCHEMA USER_PRIVILEGES

    Таблица USER_PRIVILEGES обеспечивает информацию относительно глобальных привилегий. Эта информация исходит из таблицы предоставления привилегий mysql.user.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    GRANTEE 'user_name '@'host_name' value, MySQL extension
    TABLE_CATALOG NULL, MySQL extension
    PRIVILEGE_TYPEMySQL extension
    IS_GRANTABLE MySQL extension

    Примечания:

    • Это ненормативная таблица. Требуется значения от таблицы mysql.user.

    9.6. Таблица INFORMATION_SCHEMA SCHEMA_PRIVILEGES

    Таблица SCHEMA_PRIVILEGES обеспечивает информацию относительно схемы привилегиями (базы данных). Эта информация исходит из таблицы предоставления mysql.db.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    GRANTEE ' user_name'@'host_name' value, MySQL extension
    TABLE_CATALOG NULL, MySQL extension
    TABLE_SCHEMA MySQL extension
    PRIVILEGE_TYPEMySQL extension
    IS_GRANTABLE MySQL extension

    Примечания:

    • Это ненормативная таблица. Требуется значения от таблицы mysql.db.

    9.7. Таблица INFORMATION_SCHEMA TABLE_PRIVILEGES

    Таблица TABLE_PRIVILEGES обеспечивает информацию относительно привилегий таблицы. Эта информация исходит из таблицы предоставления mysql.tables_priv.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    GRANTEE ' user_name'@'host_name' value
    TABLE_CATALOG NULL
    TABLE_SCHEMA
    TABLE_NAME
    PRIVILEGE_TYPE
    IS_GRANTABLE

    Примечания:

    • PRIVILEGE_TYPE может содержать одно (и только одно!) из этих значений: SELECT, INSERT, UPDATE, REFERENCES, ALTER, INDEX, DROP или CREATE VIEW.

    Следующие инструкции не эквивалентны:

    SELECT ... FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES
    SHOW GRANTS ...
    

    9.8. Таблица INFORMATION_SCHEMA COLUMN_PRIVILEGES

    Таблица COLUMN_PRIVILEGES обеспечивает информацию относительно привилегий столбца. Эта информация исходит из таблицы предоставления mysql.columns_priv.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    GRANTEE ' user_name'@'host_name' value
    TABLE_CATALOGNULL
    TABLE_SCHEMA
    TABLE_NAME
    COLUMN_NAME
    PRIVILEGE_TYPE
    IS_GRANTABLE

    Примечания:

    • В выводе из SHOW FULL COLUMNS все привилегии перечислены в одном поле и в нижнем регистре, например, select, insert, update, references. В COLUMN_PRIVILEGES имеется одна привилегия на строку верхнего регистра.

    • PRIVILEGE_TYPE может содержать одно (и только одно!) из этих значений: SELECT, INSERT, UPDATE и REFERENCES.

    • Если пользователь имеет опцию GRANT OPTION, IS_GRANTABLE должна быть YES. Иначе IS_GRANTABLE будет NO. Вывод не вносит в список GRANT OPTION как отдельную привилегию.

    Следующие инструкции не эквивалентны:

    SELECT ... FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES
    SHOW GRANTS ...
    

    9.9. Таблица INFORMATION_SCHEMA CHARACTER_SETS

    Таблица CHARACTER_SETS обеспечивает информацию относительно доступных наборов символов.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    CHARACTER_SET_NAMECharset
    DEFAULT_COLLATE_NAMEDefault collation
    DESCRIPIONDescription MySQL extension
    MAXLENMaxlen MySQL extension

    Следующие инструкции эквивалентны:

    SELECT * FROM INFORMATION_SCHEMA.CHARACTER_SETS
             [WHERE name LIKE 'wild']
             SHOW CHARACTER SET [LIKE 'wild']
    

    9.10. Таблица INFORMATION_SCHEMA COLLATIONS

    Таблица COLLATIONS обеспечивает информацию относительно объединений для каждого набора символов.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    COLLATION_NAMECollation
    CHARACTER_SET_NAMECharset MySQL extension
    IDId MySQL extension
    IS_DEFAULTDefault MySQL extension
    IS_COMPILEDCompiled MySQL extension
    SORTLENSortlen MySQL extension

    Следующие инструкции эквивалентны:

    SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLLATIONS
           [WHERE collation_name LIKE 'wild']
           SHOW COLLATION [LIKE 'wild']
    

    9.11. Таблица INFORMATION_SCHEMA COLLATION_CHARACTER_SET_APPLICABILITY

    Таблица COLLATION_CHARACTER_SET_APPLICABILITY указывает то, какому объединению соответствует набор символов. Столбцы эквивалентны к первым двум полям вывода SHOW COLLATION.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    COLLATION_NAMECollation
    CHARACTER_SET_NAMECharset

    9.12. Таблица INFORMATION_SCHEMA TABLE_CONSTRAINTS

    Таблица TABLE_CONSTRAINTS описывает, которые таблицы имеют ограничения.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    CONSTRAINT_CATALOGNULL
    CONSTRAINT_SCHEMA
    CONSTRAINT_NAME
    TABLE_SCHEMA
    TABLE_NAME
    CONSTRAINT_TYPE

    Примечания:

    • Значение CONSTRAINT_TYPE может быть UNIQUE, PRIMARY KEY или FOREIGN KEY.

    • Информация UNIQUE и PRIMARY KEY соответствует полю Key_name в выводе SHOW INDEX, если поле Non_unique равно 0.

    • Столбец CONSTRAINT_TYPE может содержать одно из этих значений: UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK. Это столбец CHAR (не ENUM). Значение CHECK недоступно, пока пакет не поддерживает CHECK.

    9.13. Таблица INFORMATION_SCHEMA KEY_COLUMN_USAGE

    Таблица KEY_COLUMN_USAGE описывает, которые столбцы ключа имеют ограничения.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    CONSTRAINT_CATALOG NULL
    CONSTRAINT_SCHEMA
    CONSTRAINT_NAME
    TABLE_CATALOG
    TABLE_SCHEMA
    TABLE_NAME
    COLUMN_NAME
    ORDINAL_POSITION
    POSITION_IN_UNIQUE_CONSTRAINT
    REFERENCED_TABLE_SCHEMA
    REFERENCED_TABLE_NAME
    REFERENCED_COLUMN_NAME

    Примечания:

    • Если ограничение внешний ключ, то это столбец внешнего ключа, не столбец, а не тот столюец, на который внешний ключ ссылается.

    • Значение ORDINAL_POSITION позиция столбца внутри ограничения, а не позиция столбца внутри таблицы. Позиции столбца пронумерованы, начиная с 1.

    • Значение POSITION_IN_UNIQUE_CONSTRAINT NULL для ограничений unique и primary-key. Для ограничений foreign-key это порядковая позиция в ключе таблицы, которая вызвана.

      Например, предположите, что имеется две таблицы с именами t1 и t3, которые имеют следующие определения:

      CREATE TABLE t1 (s1 INT, s2 INT, s3 INT, PRIMARY KEY(s3)) ENGINE=InnoDB;
      CREATE TABLE t3 (s1 INT, s2 INT, s3 INT, KEY(s1),
             CONSTRAINT CO FOREIGN KEY (s2) REFERENCES t1(s3)) ENGINE=InnoDB;
      

      Для этих двух таблиц таблица KEY_COLUMN_USAGE имеет две строки:

      • Одна строка с CONSTRAINT_NAME = 'PRIMARY', TABLE_NAME = 't1', COLUMN_NAME = 's3', ORDINAL_POSITION = 1, POSITION_IN_UNIQUE_CONSTRAINT = NULL.

      • Одна строка с CONSTRAINT_NAME = 'CO', TABLE_NAME = 't3', COLUMN_NAME = 's2', ORDINAL_POSITION = 1, POSITION_IN_UNIQUE_CONSTRAINT = 1.

    9.14. Таблица INFORMATION_SCHEMA ROUTINES

    Таблица ROUTINES обеспечивает информацию относительно сохраненных подпрограмм (процедуры и функций). Таблица ROUTINES не включает определяемые пользователем функции (UDF).

    Столбец mysql.proc name указывает столбец таблицы mysql.proc, который соответствует столбцу таблицы INFORMATION_SCHEMA.ROUTINES.

    INFORMATION_SCHEMA Name mysql.proc Name Remarks
    SPECIFIC_NAMEspecific_name
    ROUTINE_CATALOG NULL
    ROUTINE_SCHEMAdb
    ROUTINE_NAMEname
    ROUTINE_TYPEtype {PROCEDURE|FUNCTION}
    DTD_IDENTIFIER (data type descriptor)
    ROUTINE_BODYSQL
    ROUTINE_DEFINITIONbody
    EXTERNAL_NAME NULL
    EXTERNAL_LANGUAGElanguage NULL
    PARAMETER_STYLE SQL
    IS_DETERMINISTICis_deterministic
    SQL_DATA_ACCESSsql_data_access
    SQL_PATH NULL
    SECURITY_TYPEsecurity_type
    CREATEDcreated
    LAST_ALTEREDmodified
    SQL_MODEsql_mode MySQL extension
    ROUTINE_COMMENTcomment MySQL extension
    DEFINERdefiner MySQL extension

    Примечания:

    • MySQL вычисляет EXTERNAL_LANGUAGE так:

      • Если mysql.proc.language='SQL', EXTERNAL_LANGUAGE равен NULL

      • Иначе EXTERNAL_LANGUAGE равен mysql.proc.language. Однако, пока не имеется внешних языков, так что это всегда NULL.

    9.15. Таблица INFORMATION_SCHEMA VIEWS

    Таблица VIEWS обеспечивает информацию относительно view в базах данных. Вы должны иметь привилегию SHOW VIEW, чтобы обратиться к этой таблице.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    TABLE_CATALOG NULL
    TABLE_SCHEMA
    TABLE_NAME
    VIEW_DEFINITION
    CHECK_OPTION
    IS_UPDATABLE
    DEFINER
    SECURITY_TYPE

    Примечания:

    • Столбец VIEW_DEFINITION показывает большинство из того, что Вы видите в поле Create Table, которое выводится SHOW CREATE VIEW. Пропустите слова перед SELECT и перед WITH CHECK OPTION. Предположите, что первоначальная инструкция была такой:

      CREATE VIEW v AS SELECT s2,s1 FROM t WHERE s1 > 5 ORDER BY s1
             WITH CHECK OPTION;
      

      Затем определение этого view выглядит следующим образом:

      SELECT s2,s1 FROM t WHERE s1 > 5 ORDER BY s1
      
    • Столбец CHECK_OPTION всегда имеет значение NONE.

    • Столбец IS_UPDATABLE равен YES, если view обновляемый, в противном случае NO.

    • Столбец DEFINER указывает, кто определил view. SECURITY_TYPE имеет значение DEFINER или INVOKER.

    9.16. Таблица INFORMATION_SCHEMA TRIGGERS

    Таблица TRIGGERS обеспечивает информацию относительно триггеров. Вы должны иметь привилегию SUPER, чтобы обратиться к этой таблице.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    TRIGGER_CATALOG NULL
    TRIGGER_SCHEMA
    TRIGGER_NAMETrigger
    EVENT_MANIPULATIONEvent
    EVENT_OBJECT_CATALOG NULL
    EVENT_OBJECT_SCHEMA
    EVENT_OBJECT_TABLETable
    ACTION_ORDER 0
    ACTION_CONDITION NULL
    ACTION_STATEMENTStatement
    ACTION_ORIENTATION ROW
    ACTION_TIMINGTiming
    ACTION_REFERENCE_OLD_TABLE NULL
    ACTION_REFERENCE_NEW_TABLE NULL
    ACTION_REFERENCE_OLD_ROW OLD
    ACTION_REFERENCE_NEW_ROW NEW
    CREATED NULL (0)
    SQL_MODE MySQL extension
    DEFINER MySQL extension

    Примечания:

    • Столбцы TRIGGER_SCHEMA и TRIGGER_NAME содержат имя базы данных, в которой находится триггер и его имя, соответственно.

    • Столбец EVENT_MANIPULATION содержит одно из значений 'INSERT', 'DELETE' или 'UPDATE'.

    • Каждый триггер связан точно с одной таблицей. Столбцы EVENT_OBJECT_SCHEMA и EVENT_OBJECT_TABLE содержат базу данных, в которой эта таблица расположена, и имя таблицы.

    • Инструкция ACTION_ORDER содержит порядковую позицию действия триггера внутри списка подобных в той же самой таблице. В настоящее время это значение всегда 0, потому что невозможно иметь больше, чем один триггер с теми же самыми EVENT_MANIPULATION и ACTION_TIMING на той же самой таблице.

    • Столбец ACTION_STATEMENT содержит инструкцию, которая будет выполнена, когда вызывается триггер. Это текст, отображаемый в столбце Statement вывода SHOW TRIGGERS. Обратите внимание, что на эти тексты распространяется кодирование в UTF-8.

    • Столбец ACTION_ORIENTATION всегда содержит значения 'ROW'.

    • Столбец ACTION_TIMING содержит одно из двух значений: 'BEFORE' или 'AFTER'.

    • Столбцы ACTION_REFERENCE_OLD_ROW и ACTION_REFERENCE_NEW_ROW содержат старые и новые идентификаторы столбцов, соответственно. Это означает, что ACTION_REFERENCE_OLD_ROW всегда содержит значение 'OLD' и ACTION_REFERENCE_NEW_ROW 'NEW'.

    • Столбец SQL_MODE показывает режим сервера SQL, который был установлен, когда триггер был создан (и таким образом, который остается в силе для триггера, когда это вызывается, независимо от текущей ситуации). Возможный диапазон значений для этого столбца такой же, как для переменной системы sql_mode.

    • Столбец DEFINER был добавлен в MySQL 5.1.2. DEFINER указывает, кто определил триггер.

    • Следующие столбцы в настоящее время всегда содержат NULL: TRIGGER_CATALOG, EVENT_OBJECT_CATALOG, ACTION_CONDITION, ACTION_REFERENCE_OLD_TABLE, ACTION_REFERENCE_NEW_TABLE и CREATED.

    Пример, используем ins_sum:

    mysql> SELECT * FROM INFORMATION_SCHEMA.TRIGGERS\G
    *************************** 1. row ***************************
    TRIGGER_CATALOG: NULL
    TRIGGER_SCHEMA: test
    TRIGGER_NAME: ins_sum
    EVENT_MANIPULATION: INSERT
    EVENT_OBJECT_CATALOG: NULL
    EVENT_OBJECT_SCHEMA: test
    EVENT_OBJECT_TABLE: account
    ACTION_ORDER: 0
    ACTION_CONDITION: NULL
    ACTION_STATEMENT: SET @sum = @sum + NEW.amount
    ACTION_ORIENTATION: ROW
    ACTION_TIMING: BEFORE
    ACTION_REFERENCE_OLD_TABLE: NULL
    ACTION_REFERENCE_NEW_TABLE: NULL
    ACTION_REFERENCE_OLD_ROW: OLD
    ACTION_REFERENCE_NEW_ROW: NEW
    CREATED: NULL
    SQL_MODE:
    DEFINER: me@localhost
    

    9.17. Таблица INFORMATION_SCHEMA PLUGINS

    Таблица PLUGINS обеспечивает информацию относительно расширений сервера.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    PLUGIN_NAMEName MySQL extension
    PLUGIN_VERSIONMySQL extension
    PLUGIN_STATUSStatus MySQL extension
    PLUGIN_TYPEType MySQL extension
    PLUGIN_TYPE_VERSION MySQL extension
    PLUGIN_LIBRARYLibrary MySQL extension
    PLUGIN_LIBRARY_VERSION MySQL extension
    PLUGIN_AUTHORMySQL extension
    PLUGIN_DESCRIPTION MySQL extension

    Примечания:

    • Таблица PLUGINS ненормативная. Это было добавлено в MySQL 5.1.5.

    9.18. Таблица INFORMATION_SCHEMA ENGINES

    Таблица ENGINES обеспечивает информацию относительно типов памяти.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    ENGINEEngine MySQL extension
    SUPPORTSupport MySQL extension
    COMMENTComment MySQL extension
    TRANSACTIONSTransactions MySQL extension
    XAXA MySQL extension
    SAVEPOINTSSavepoints MySQL extension

    Примечания:

    • Таблица ENGINES ненормативная. Это было добавлено в MySQL 5.1.5.

    9.19. Таблица INFORMATION_SCHEMA PARTITIONS

    Таблица PARTITIONS обеспечивают информацию относительно разделов таблицы.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    TABLE_CATALOGMySQL extension
    TABLE_SCHEMA MySQL extension
    TABLE_NAME MySQL extension
    PARTITION_NAMEMySQL extension
    SUBPARTITION_NAME MySQL extension
    PARTITION_ORDINAL_POSITION MySQL extension
    SUBPARTITION_ORDINAL_POSITION MySQL extension
    PARTITION_METHOD MySQL extension
    SUBPARTITION_METHOD MySQL extension
    PARTITION_EXPRESSION MySQL extension
    SUBPARTITION_EXPRESSION MySQL extension
    PARTITION_DESCRIPTION MySQL extension
    TABLE_ROWS MySQL extension
    AVG_ROW_LENGTHMySQL extension
    DATA_LENGTH MySQL extension
    MAX_DATA_LENGTH MySQL extension
    INDEX_LENGTH MySQL extension
    DATA_FREE MySQL extension
    CREATE_TIME MySQL extension
    UPDATE_TIME MySQL extension
    CHECK_TIME MySQL extension
    CHECKSUM MySQL extension
    PARTITION_COMMENT MySQL extension
    NODEGROUP MySQL extension
    TABLESPACE_NAME MySQL extension

    Примечания:

    • Таблица PARTITIONS ненормативная. Это было добавлено в MySQL 5.1.6.

      Каждая запись в этой таблице соответствует индивидуальному разделу или подразделу разбитой на разделы таблицы.

    • TABLE_CATALOG: Этот столбец всегда NULL.

    • TABLE_SCHEMA: Этот столбец содержит имя базы данных, которой таблица принадлежит.

    • TABLE_NAME: Этот столбец содержит имя таблицы, содержащей раздел.

    • PARTITION_NAME: Этот столбец содержит имя раздела.

    • SUBPARTITION_NAME: Если запись таблицы PARTITIONS представляет подраздел, то этот столбец содержит имя подраздела, иначе это NULL.

    • PARTITION_ORDINAL_POSITION: Все разделы индексированы в том же самом порядке, в каком они определены, 1 является номером, назначенным первому разделу. Индексация может изменяться, когда разделы добавлены, удалены и реорганизованы. Показанный номер в этом столбце отражает текущий порядок, принимая во внимание любые изменения индексации.

    • SUBPARTITION_ORDINAL_POSITION: Подразделы внутри данного раздела также индексированы и повторно проиндексированы тем же самым способом, каким все разделы индексированы внутри таблицы.

    • PARTITION_METHOD: Одно из значений RANGE, LIST, HASH, LINEAR HASH, KEY или LINEAR KEY. То есть, один из типов доступного выделения разделов.

    • SUBPARTITION_METHOD: Одно из значений HASH, LINEAR HASH, KEY или LINEAR KEY. То есть, один из типов доступного выделения подразделов.

    • PARTITION_EXPRESSION: Это выражение для функции выделения разделов, используемой в инструкции CREATE TABLE или ALTER TABLE, которая создала текущую схему выделения разделов таблицы.

      Например, рассмотрите разбитую на разделы таблицу, созданную в базе данных test, используя эту инструкцию:

      CREATE TABLE tp (c1 INT, c2 INT,
             c3 VARCHAR(25)) PARTITION
             BY HASH(c1 + c2) PARTITIONS 4;
      

      Столбец в записи PARTITION_EXPRESSION в записи таблицы PARTITIONS для раздела из этой таблицы отображает c1+c2, как показано здесь:

      mysql> SELECT DISTINCT PARTITION_EXPRESSION
           >        FROM INFORMATION_SCHEMA.PARTITIONS
           >        WHERE TABLE_NAME='tp' AND TABLE_SCHEMA='test';
      +----------------------+
      | PARTITION_EXPRESSION |
      +----------------------+
      | c1 + c2|
      +----------------------+
      1 row in set (0.09 sec)
      
    • SUBPARTITION_EXPRESSION: Это работает в том же самом режиме для выражения подвыделения разделов, которое определяет выделение подразделов для таблицы, как PARTITION_EXPRESSION делает для выражения выделения разделов, используемого, чтобы определить выделение разделов таблицы. Если таблица не имеет никаких подразделов, то этот столбец всегда хранит значение NULL.

    • PARTITION_DESCRIPTION: Этот столбец используется для разделов RANGE и LIST. Для раздела RANGE это содержит набор значений в предложении VALUES LESS THAN, которое может быть целым числом или MAXVALUE. Для раздела LIST этот столбец содержит значения, определенные в предложении VALUES IN раздела, которое является разделяемым запятыми списком целочисленных значений.

      Для разделов, чьими PARTITION_METHOD является другое, чем RANGE или LIST, этот столбец всегда будет хранить NULL.

    • TABLE_ROWS: Число строк таблиц в разделе.

    • AVG_ROW_LENGTH: средняя длина строк, сохраненных в этом разделе или подразделе, в байтах.

      Это вычисляется как DATA_LENGTH разделенное на TABLE_ROWS.

    • DATA_LENGTH: Общая длина всех строк, сохраненных в этом разделе или подразделе, в байтах. То есть, общее число байтов, сохраненных в разделе или подразделе.

    • MAX_DATA_LENGTH: Максимальное число байтов, которые могут быть сохранены в этом разделе или подразделе.

    • INDEX_LENGTH: Длина индексного файла для этого раздела или подраздела в байтах.

    • DATA_FREE: Число байт, распределенных разделу или подразделу, но им не используемых.

    • CREATE_TIME: Время создания раздела или подраздела.

    • UPDATE_TIME: Время, когда раздел или подраздел был в последний раз изменен.

    • CHECK_TIME: Последний раз, когда таблица, которой этот раздел или подраздел принадлежит, была проверена.

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

    • CHECKSUM: Значение контрольной суммы, если есть. Иначе этот столбец NULL.

    • PARTITION_COMMENT: Этот столбец содержит текст любого комментария, сделанного для раздела.

      Значение по умолчанию для этого столбца: пустая строка.

    • NODEGROUP: Это группа узлов, которой раздел принадлежит. Это релевантно только для таблиц MySQL Cluster, иначе значение этого столбца всегда 0.

    • TABLESPACE_NAME: Этот столбец содержит имя места таблицы, которому раздел принадлежит. В MySQL 5.1 значение этого столбца всегда DEFAULT.

    • Важно: если любые разбитые на разделы таблицы, созданные в MySQL версии до MySQL 5.1.6 присутствуют после обновления до MySQL 5.1.6 или позже, невозможен SELECT из, SHOW или DESCRIBE таблиц PARTITIONS.

    • Не разбитая на разделы таблица имеет одну запись в INFORMATION_SCHEMA.PARTITIONS, однако, значения столбцов PARTITION_NAME, SUBPARTITION_NAME, PARTITION_ORDINAL_POSITION, SUBPARTITION_ORDINAL_POSITION, PARTITION_METHOD, SUBPARTITION_METHOD, PARTITION_EXPRESSION, SUBPARTITION_EXPRESSION и PARTITION_DESCRIPTION все NULL. Столбец PARTITION_COMMENT в этом случае пуст.

      В MySQL 5.1 имеется также только одна запись в таблице PARTITIONS для таблицы, использующей NDBCluster. Те же самые столбцы также NULL (или пусты), как и для не разбитой на разделы таблицы.

    9.20. Таблица INFORMATION_SCHEMA EVENTS

    Таблица EVENTS обеспечивает информацию относительно планируемых событий.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    EVENT_CATALOGNULL, MySQL extension
    EVENT_SCHEMADb MySQL extension
    EVENT_NAMEName MySQL extension
    DEFINER DefinerMySQL extension
    EVENT_BODY MySQL extension
    EVENT_DEFINITION MySQL extension
    EVENT_TYPEType MySQL extension
    EXECUTE_ATExecute at MySQL extension
    INTERVAL_VALUEInterval value MySQL extension
    INTERVAL_FIELDInterval field MySQL extension
    SQL_MODE MySQL extension
    STARTSStarts MySQL extension
    ENDSEnds MySQL extension
    STATUSStatus MySQL extension
    ON_COMPLETION MySQL extension
    CREATED MySQL extension
    LAST_ALTERED MySQL extension
    LAST_EXECUTEDMySQL extension
    EVENT_COMMENTMySQL extension

    Примечания:

    • Таблица EVENTS ненормативная. Это было добавлено в MySQL 5.1.6.

    • EVENT_CATALOG: значение этого столбца всегда NULL.

    • EVENT_SCHEMA: имя схемы (базы данных), которой это событие принадлежит.

    • EVENT_NAME: имя события.

    • DEFINER: пользователь, который создал событие. Всегда отображается в формате 'user_name'@'host_name' .

    • EVENT_BODY: Язык, используемый для инструкций в предложении DO события, в MySQL 5.1 это всегда SQL. Этот столбец был добавлен в MySQL 5.1.12. Это не должно быть спутано со столбцом того же самого имени (теперь называется EVENT_DEFINITION) в старых версиях MySQL.

    • EVENT_DEFINITION: текст инструкции SQL, составляющей предложение DO события, другими словами, инструкция, выполненная этим событием.

      Обратите внимание: до MySQL 5.1.12 этот столбец назывался EVENT_BODY.

    • EVENT_TYPE: одно из двух значений ONE TIME или RECURRING.

    • EXECUTE_AT: для одноразового события это значение the DATETIME, определенное в предложении AT инструкции CREATE EVENT, используемой, чтобы создать событие, или последней инструкции ALTER EVENT, которая изменила событие. Значение, показанное в этом столбце, отражает добавление или вычитание любого значения INTERVAL, включенного в предложение AT события. Например, если событие создано, используя ON SCHEDULE AT CURRENT_TIMESTAMP + '1:6' DAY_HOUR, а событие было создано в 2006-02-09 14:05:30, значение, показанное в этом столбце, будет '2006-02-10 20:05:30'.

      Если синхронизация события определена предложением EVERY вместо предложения AT (то есть, если событие повторяется), значение этого столбца NULL.

    • INTERVAL_VALUE: для многоразовых событий этот столбец содержит числовую часть предложения EVERY события.

      Для одноразового события (то есть, события, чья синхронизация определена предложением AT) значение этого столбца NULL.

    • INTERVAL_FIELD: для многоразовых событий этот столбец содержит модульную часть предложения EVERY, управляя синхронизацией события с префиксом 'INTERVAL_'. Таким образом, этот столбец содержит значение типа 'INTERVAL_YEAR', 'INTERVAL_QUARTER', 'INTERVAL_DAY' или нечто подобное. Для одноразового события значение этого столбца NULL.

    • SQL_MODE: режим SQL во время создания или изменения события.

    • STARTS: для многоразовых событий, чье определение включает предложение STARTS, этот столбец содержит соответствующее значение DATETIME. Как и со столбцом EXECUTE_AT, это значение решает любые используемые выражения.

      Если не имеется никакого предложения STARTS, воздействующего на синхронизацию события, этот столбец пуст. До MySQL 5.1.8 это содержало NULL в таких случаях.

    • ENDS: то же самое, но для предложения ENDS.

    • STATUS: одно из двух значений: ENABLED или DISABLED.

    • ON_COMPLETION: одно из двух значений: PRESERVE или NOT PRESERVE.

    • CREATED: дата и время, когда событие было создано. Это значение DATETIME.

    • LAST_ALTERED: дата и время, когда событие было в последний раз изменено. Это значение DATETIME. Если событие не изменялось, начиная с создания, этот столбец хранит то же самое значение, что и столбец CREATED.

    • LAST_EXECUTED: дата и время, когда событие в последний раз выполнилось. Значение DATETIME. Если событие никогда не выполнялось, значение этого столбца NULL.

    • EVENT_COMMENT: текст комментария, если событие его имеет. Если не имеется никакого комментария, значение этого столбца пустая строка.

    Пример: предположите, что пользователь jon@ghidora создает событие e_daily, а затем изменяет его через несколько минут, используя инструкцию ALTER EVENT, как показано здесь:

    DELIMITER |
    CREATE EVENT e_daily ON SCHEDULE EVERY 1 DAY
           STARTS CURRENT_TIMESTAMP + INTERVAL 6 HOUR DISABLE
           COMMENT 'Saves total number of sessions and
                    clears the table once per day.'
           DO BEGIN INSERT INTO site_activity.totals (when, total)
           SELECT CURRENT_TIMESTAMP, COUNT(*) FROM site_activity.sessions;
           DELETE FROM site_activity.sessions;
       END |
    DELIMITER ;
    ALTER EVENT e_daily ENABLED;
    

    Обратите внимание, что комментарии могут охватывать много строк.

    Этот пользователь может затем выполнять следующую инструкцию SELECT и получать показанный вывод:

    mysql> SELECT * FROM INFORMATION_SCHEMA.EVENTS
         >          WHERE EVENT_NAME = 'e_daily' AND
         >          EVENT_SCHEMA = 'myschema'\G
    
    *************************** 1. row ***************************
    EVENT_CATALOG: NULL
    EVENT_SCHEMA: myschema
    EVENT_NAME: e_daily
    DEFINER: jon@ghidora
    EVENT_BODY: BEGIN
       INSERT INTO site_activity.totals (when, total)
       SELECT CURRENT_TIMESTAMP, COUNT(*) FROM site_activity.sessions;
       DELETE FROM site_activity.sessions;
    END
    EVENT_TYPE: RECURRING
    EXECUTE_AT: NULL
    INTERVAL_VALUE: 1
    INTERVAL_FIELD: INTERVAL_DAY
    SQL_MODE: NULL
    STARTS: 2006-02-09 10:41:23
    ENDS: NULL
    STATUS: ENABLED
    ON_COMPLETION: DROP
    CREATED: 2006-02-09 14:35:35
    LAST_ALTERED: 2006-02-09 14:41:23
    LAST_EXECUTED: NULL
    EVENT_COMMENT: Saves total number of sessions and
                   clears the table once per day.
    1 row in set (0.50 sec)
    

    Важно: времена, отображаемые столбцами STARTS, ENDS и LAST_EXECUTED в настоящее время даны в терминах универсального времени (GMT или UTC), независимо от установки часового пояса сервера. Это верно и для столбцов starts, ends и last_executed в таблице mysql.event, а также для столбцов Starts и Ends в таблице SHOW [FULL] EVENTS. Зато столбцы CREATED и LAST_ALTERED используют часовой пояс сервера (также, как столбцы created и last_altered в таблице mysql.event), чтобы Вам жизнь медом не казалась.

    Например, событие e_daily, показанное ранее, было создано на компьютере в Brisbane, Australia, в 14:35:35 9 февраля 2006. Восточное стандартное время Австралии, которое также может быть выражено как GMT+10.00. Определение события модифицировалось (используя ALTER EVENT) на несколько минут позже, в 14:41:23. Это значения, отображаемые для CREATED и LAST_ALTERED. Событие планируется, чтобы начать выполнять 6 часов спустя, в 20:41:23 в тот же самый лень, по местному времени. Вычитание 10 часов из этого, чтобы получить универсальное время выдает 10:41:23, и это то значение, которое показывается для STARTS.

    На это использование универсального времени нельзя положиться в прикладных программах, поскольку ожидается изменить на сервере местное время (Глюк #16420).

    9.21. Таблица INFORMATION_SCHEMA FILES

    Таблица FILES обеспечивает информацию относительно файлов, в которых сохранены данные дисковых таблиц MySQL NDB.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    FILE_ID MySQL extension
    FILE_NAME MySQL extension
    FILE_TYPE MySQL extension
    TABLESPACE_NAME MySQL extension
    TABLE_CATALOG MySQL extension
    TABLE_SCHEMA MySQL extension
    TABLE_NAME MySQL extension
    LOGFILE_GROUP_NAME MySQL extension
    LOGFILE_GROUP_NUMBER MySQL extension
    ENGINE MySQL extension
    FULLTEXT_KEYS MySQL extension
    DELETED_ROWS MySQL extension
    UPDATE_COUNT MySQL extension
    FREE_EXTENTS MySQL extension
    TOTAL_EXTENTS MySQL extension
    EXTENT_SIZE MySQL extension
    INITIAL_SIZE MySQL extension
    MAXIMUM_SIZE MySQL extension
    AUTOEXTEND_SIZE MySQL extension
    CREATION_TIME MySQL extension
    LAST_UPDATE_TIME MySQL extension
    LAST_ACCESS_TIME MySQL extension
    RECOVER_TIME MySQL extension
    TRANSACTION_COUNTER MySQL extension
    VERSION MySQL extension
    ROW_FORMAT MySQL extension
    TABLE_ROWS MySQL extension
    AVG_ROW_LENGTH MySQL extension
    DATA_LENGTH MySQL extension
    MAX_DATA_LENGTH MySQL extension
    INDEX_LENGTH MySQL extension
    DATA_FREE MySQL extension
    CREATE_TIME MySQL extension
    UPDATE_TIME MySQL extension
    CHECK_TIME MySQL extension
    CHECKSUM MySQL extension
    STATUS MySQL extension
    EXTRA MySQL extension

    Примечания:

    • FILE_ID значения столбца автосгенерированы.

    • FILE_NAME имя журнала UNDO, созданного CREATE LOGFILE GROUP или ALTER LOGFILE GROUP, либо файла данных, созданного CREATE TABLESPACE или ALTER TABLESPACE.

    • FILE_TYPE одно из значений UNDOFILE или DATAFILE.

    • TABLESPACE_NAME имя пространства таблиц, с которым файл связан.

    • В MySQL 5.1 значение столбца TABLESPACE_CATALOG всегда NULL.

    • TABLE_NAME имя дисковой таблицы данных, с которой файл связан, если есть.

    • Столбец LOGFILE_GROUP_NAME дает имя группы журнала, которой журнал или файл данных принадлежит.

    • Для журнала UNDO LOGFILE_GROUP_NUMBER содержит автосгенерированный номер ID группы журналов, к которой журнал принадлежит.

    • Для журнала данных MySQL Cluster или файла данных, значение столбца ENGINE всегда NDB или NDBCLUSTER.

    • Для журнала данных MySQL Cluster или файла данных, значение столбца FULLTEXT_KEYS всегда пусто.

    • Столбец FREE EXTENTS отображает число блоков, которые еще не использовались файлом. Столбец TOTAL EXTENTS показывает общее число блоков, распределенных файлу.

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

      SELECT TOTAL_EXTENTS - FREE_EXTENTS AS extents_used
             FROM INFORMATION_SCHEMA.FILES
             WHERE FILE_NAME = 'myfile.dat';
      

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

      SELECT (TOTAL_EXTENTS - FREE_EXTENTS) * EXTENT_SIZE AS bytes_used
             FROM INFORMATION_SCHEMA.FILES
             WHERE FILE_NAME = 'myfile.dat';
      

      Точно так же Вы можете оценивать количество места, которое остается доступным в данном файле, умножая FREE_EXTENTS на EXTENT_SIZE:

      SELECT FREE_EXTENTS * EXTENT_SIZE AS bytes_free
             FROM INFORMATION_SCHEMA.FILES
             WHERE FILE_NAME = 'myfile.dat';
      

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

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

      Размер блока может быть установлен в инструкции CREATE TABLESPACE.

    • Столбец INITIAL_SIZE показывает размер в байтах файла. Это то же самое значение, которое использовалось в предложении INITIAL_SIZE команд CREATE LOGFILE GROUP, ALTER LOGFILE GROUP, CREATE TABLESPACE или ALTER TABLESPACE использовавшихся, чтобы создать файл.

      Для файлов MySQL 5.1 Cluster Disk Data значение столбца MAXIMUM_SIZE всегда такое же, как INITIAL_SIZE, а столбец AUTOEXTEND_SIZE всегда пуст.

    • Столбец CREATION_TIME показывает дату и время, когда файл был создан. LAST_UPDATE_TIME отображает дату и время, когда файл был последний раз изменен. LAST_ACCESSED обеспечивает дату и время, когда к файлу последний раз обращался сервер.

      В настоящее время значения этих столбцов сообщены операционной системой и не обеспечены NDB. Там, где никакое значение не обеспечивается операционной системой, эти столбцы отображаются 0000-00-00 00:00:00.

    • Для файлов данных MySQL Cluster значение столбцов RECOVER_TIME и TRANSACTION_COUNTER всегда 0.

    • Для файлов данных MySQL 5.1 Cluster следующие столбцы всегда NULL:

      • VERSION

      • ROW_FORMAT

      • TABLE_ROWS

      • AVG_ROW_LENGTH

      • DATA_LENGTH

      • MAX_DATA_LENGTH

      • INDEX_LENGTH

      • DATA_FREE

      • CREATE_TIME

      • UPDATE_TIME

      • CHECK_TIME

      • CHECKSUM

    • Для файлов данных MySQL Cluster значение столбца STATUS всегда NORMAL.

    • Для файлов данных MySQL Cluster столбец EXTRA показывает, которому узлу данных принадлежит файл, поскольку каждый узел данных имеет собственную копию файла. Например, предположите, что Вы используете эту инструкцию относительно MySQL Cluster с четырьмя узлами данных:

      CREATE LOGFILE GROUP mygroup
             ADD UNDOFILE 'new_undo.dat'
             INITIAL_SIZE 2G ENGINE NDB;
      

      После удачного выполнения инструкции CREATE LOGFILE GROUP Вы должны видеть результат, подобный показанному здесь для этого запроса к таблице FILES:

      mysql> SELECT LOGFILE_GROUP_NAME, FILE_TYPE, EXTRA
          ->        FROM INFORMATION_SCHEMA.FILES
          ->        WHERE FILE_NAME = 'new_undo.dat';
      +--------------------+-----------+----------------+
      | LOGFILE_GROUP_NAME | FILE_TYPE | EXTRA          |
      +--------------------+-----------+----------------+
      | mygroup            | UNDO FILE | CLUSTER_NODE=3 |
      | mygroup            | UNDO FILE | CLUSTER_NODE=4 |
      | mygroup            | UNDO FILE | CLUSTER_NODE=5 |
      | mygroup            | UNDO FILE | CLUSTER_NODE=6 |
      +--------------------+-----------+----------------+
      4 rows in set (0.01 sec)
      
    • Таблица FILES ненормативная. Это было добавлено в MySQL 5.1.6.

    • Не имеется никаких команд SHOW, связанных с таблицей FILES.

    9.22. Таблица INFORMATION_SCHEMA PROCESSLIST

    Таблица PROCESSLIST обеспечивает информацию, относительно выполняемых сервером потоков.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    IDIdMySQL extension
    USERUserMySQL extension
    HOSTHost MySQL extension
    DBdb MySQL extension
    COMMANDCommand MySQL extension
    TIMETime MySQL extension
    STATEState MySQL extension
    INFOInfo MySQL extension

    Примечания:

    • Таблица PROCESSLIST ненормативная. Это было добавлено в MySQL 5.1.7.

    • Подобно выводу из соответствующей инструкции SHOW, таблица PROCESSLIST покажет информацию только относительно Ваших собственных потоков, если Вы не имеете привилегию PROCESS, тогда Вы будете видеть информацию относительно других потоков. Как анонимный пользователь Вы не можете видеть любые строки вообще.

    • Если инструкция SQL обращается INFORMATION_SCHEMA.PROCESSLIST, MySQL заполнит всю таблицу один раз, когда, операторное выполнение начинается, так что гарантируется непротиворечивость чтения в течение инструкции. Не имеется никакой непротиворечивости чтения для многооператорной транзакции.

    Следующие инструкции эквивалентны:

    SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
    SHOW PROCESSLIST
    

    9.23. Таблица INFORMATION_SCHEMA REFERENTIAL_CONSTRAINTS

    Таблица REFERENTIAL_CONSTRAINTS обеспечивает информацию относительно внешних ключей.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    CONSTRAINT_CATALOG NULL
    CONSTRAINT_SCHEMA
    CONSTRAINT_NAME
    UNIQUE_CONSTRAINT_CATALOG NULL
    UNIQUE_CONSTRAINT_SCHEMA
    UNIQUE_CONSTRAINT_NAME
    MATCH_OPTION
    UPDATE_RULE
    DELETE_RULE
    TABLE_NAME

    Примечания:

    • Таблица REFERENTIAL_CONSTRAINTS была добавлена в MySQL 5.1.10.

    • TABLE_NAME имеет то же самое значение, что и TABLE_NAME в INFORMATION_SCHEMA.TABLE_CONSTRAINTS.

    • CONSTRAINT_SCHEMA и CONSTRAINT_NAME идентифицируют внешний ключ.

    • UNIQUE_CONSTRAINT_SCHEMA и UNIQUE_CONSTRAINT_NAME идентифицируют вызванный ключ.

    • Единственное допустимое значение в это время для MATCH_OPTION: NONE.

    • Возможные значения для UPDATE_RULE или DELETE_RULE: CASCADE, SET NULL, SET DEFAULT, RESTRICT, NO ACTION.

    9.24. Таблицы INFORMATION_SCHEMA GLOBAL_STATUS и SESSION_STATUS

    Таблицы GLOBAL_STATUS и SESSION_STATUS обеспечивают информацию относительно переменных состояния сервера. Их содержание соответствует информации, произведенной инструкциями SHOW GLOBAL STATUS и SHOW SESSION STATUS.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    VARIABLE_NAMEVariable_name
    VARIABLE_VALUEValue

    Примечания:

    • Таблицы GLOBAL_STATUS и SESSION_STATUS были добавлены в MySQL 5.1.12.

    • Столбец VARIABLE_VALUE имеет тип BIGINT. Немногие переменные состояния, которые имеют значения нецелого числа, приведены к значениям BIGINT.

    9.25. Таблицы INFORMATION_SCHEMA GLOBAL_VARIABLES и SESSION_VARIABLES

    Таблицы GLOBAL_VARIABLES и SESSION_VARIABLES обеспечивают информацию относительно переменных состояния сервера. Их содержание соответствует информации, произведенной инструкциями SHOW GLOBAL VARIABLES и SHOW SESSION VARIABLES.

    INFORMATION_SCHEMA Name SHOW Name Remarks
    VARIABLE_NAMEVariable_name
    VARIABLE_VALUEValue

    Примечания:

    • Таблицы GLOBAL_VARIABLES и SESSION_VARIABLES были добавлены в MySQL 5.1.12.

    9.26. Другие таблицы INFORMATION_SCHEMA

    Авторы предполагают выполнять дополнительные таблицы в INFORMATION_SCHEMA. В частности, они подтверждают потребность в таблице PARAMETERS.

    9.27. Расширения инструкции SHOW

    Некоторые расширения к инструкциям SHOW сопровождают реализацию INFORMATION_SCHEMA:

    • SHOW может использоваться, чтобы получить информацию относительно структуры INFORMATION_SCHEMA.

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

    INFORMATION_SCHEMA информационная база данных, так что имя включено в вывод из SHOW DATABASES. Точно так же SHOW TABLES может использоваться с INFORMATION_SCHEMA, чтобы получить список таблиц:

    mysql> SHOW TABLES FROM INFORMATION_SCHEMA;
    +---------------------------------------+
    | Tables_in_information_schema          |
    +---------------------------------------+
    | CHARACTER_SETS                        |
    | COLLATIONS                            |
    | COLLATION_CHARACTER_SET_APPLICABILITY |
    | COLUMNS                               |
    | COLUMN_PRIVILEGES                     |
    | ENGINES                               |
    | EVENTS                                |
    | FILES                                 |
    | KEY_COLUMN_USAGE                      |
    | PARTITIONS                            |
    | PLUGINS                               |
    | PROCESSLIST                           |
    | ROUTINES                              |
    | SCHEMATA                              |
    | SCHEMA_PRIVILEGES                     |
    | STATISTICS                            |
    | TABLES                                |
    | TABLE_CONSTRAINTS                     |
    | TABLE_PRIVILEGES                      |
    | TRIGGERS                              |
    | USER_PRIVILEGES                       |
    | VIEWS                                 |
    +---------------------------------------+
    22 rows in set (0.04 sec)
    

    SHOW COLUMNS и DESCRIBE могут отображать информацию относительно столбцов в индивидуальных таблицах INFORMATION_SCHEMA.

    Несколько инструкций SHOW были расширены, чтобы позволить предложение WHERE:

    SHOW CHARACTER SET
    SHOW COLLATION
    SHOW COLUMNS
    SHOW DATABASES
    SHOW FUNCTION STATUS
    SHOW KEYS
    SHOW OPEN TABLES
    SHOW PROCEDURE STATUS
    SHOW STATUS
    SHOW TABLE STATUS
    SHOW TABLES
    SHOW VARIABLES
    

    Предложение WHERE, если представлено, оценено для имен столбцов, отображаемых инструкцией SHOW. Например, инструкция SHOW CHARACTER SET производит эти столбцы вывода:

    mysql> SHOW CHARACTER SET;
    +----------+-----------------------------+---------------------+--------+
    | Charset  | Description                 | Default collation   | Maxlen |
    +----------+-----------------------------+---------------------+--------+
    |     big5 | Big5 Traditional Chinese    | big5_chinese_ci     | 2      |
    |     dec8 | DEC West European           | dec8_swedish_ci     | 1      |
    |    cp850 | DOS West European           | cp850_general_ci    | 1      |
    |      hp8 | HP West European            | hp8_english_ci      | 1      |
    |    koi8r | KOI8-R Relcom Russian       | koi8r_general_ci    | 1      |
    |   latin1 | cp1252 West European        | latin1_swedish_ci   | 1      |
    |   latin2 | ISO 8859-2 Central European | latin2_general_ci   | 1      |
    ...
    

    Используя предложение WHERE с SHOW CHARACTER SET, Вы обратились бы к тем именам столбца. Например, следующий оператор отображает информацию относительно наборов символов, для которых заданное по умолчанию объединение содержит строку 'japanese':

    mysql> SHOW CHARACTER SET WHERE `Default collation` LIKE '%japanese%';
    +---------+---------------------------+---------------------+--------+
    | Charset | Description               |   Default collation | Maxlen |
    +---------+---------------------------+---------------------+--------+
    |    ujis |           EUC-JP Japanese |    ujis_japanese_ci | 3      |
    |    sjis |        Shift-JIS Japanese |    sjis_japanese_ci | 2      |
    |   cp932 | SJIS for Windows Japanese |   cp932_japanese_ci | 2      |
    | eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci | 3      |
    +---------+---------------------------+---------------------+--------+
    

    Эта инструкция отображает многобайтовые наборы символов:

    mysql> SHOW CHARACTER SET WHERE Maxlen > 1;
    +---------+---------------------------+---------------------+--------+
    | Charset | Description               | Default collation   | Maxlen |
    +---------+---------------------------+---------------------+--------+
    |    big5 |  Big5 Traditional Chinese |     big5_chinese_ci | 2      |
    |    ujis |           EUC-JP Japanese |    ujis_japanese_ci | 3      |
    |    sjis |        Shift-JIS Japanese |    sjis_japanese_ci | 2      |
    |   euckr |             EUC-KR Korean |     euckr_korean_ci | 2      |
    |  gb2312 | GB2312 Simplified Chinese |   gb2312_chinese_ci | 2      |
    |     gbk |    GBK Simplified Chinese |      gbk_chinese_ci | 2      |
    |    utf8 |             UTF-8 Unicode |     utf8_general_ci | 3      |
    |    ucs2 |             UCS-2 Unicode |     ucs2_general_ci | 2      |
    |   cp932 | SJIS for Windows Japanese |   cp932_japanese_ci | 2      |
    | eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci | 3      |
    +---------+---------------------------+---------------------+--------+
    

    9.28. MySQL 5 FAQ INFORMATION_SCHEMA

    9.28.1: Имеется ли форум для обсуждения INFORMATION_SCHEMA?

    Да. http://forums.mysql.com/list.php?101.

    9.28.2: Где я могу найти спецификацию ANSI SQL 2003 для INFORMATION_SCHEMA?

    К сожалению, официальные спецификации недоступны свободно. ANSI делает их доступными только за денежку. Однако, имеются доступные книги, например, SQL-99 Complete, Really by Peter Gulutzan and Trudy Pelzer, которые дают всесторонний краткий обзор стандарта, включая INFORMATION_SCHEMA.

    9.28.3: Каково различие между Oracle Data Dictionary и MySQL INFORMATION_SCHEMA?

    Oracle и MySQL обеспечивают метаданные в таблицах. Однако, Oracle и MySQL используют различные имена таблиц и столбцов. Реализация MySQL более подобна DB2 и SQL Server, которые также поддерживают INFORMATION_SCHEMA как определено в стандарте SQL.

    9.28.4: Я могу изменять таблицы, найденные в базе данных INFORMATION_SCHEMA?

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

    atus-table">9.24. Таблицы INFORMATION_SCHEMA GLOBAL_STATUS и SESSION_STATUS

    Таблицы GLOBAL_STATUS и SESSION_STATUS обеспечивают информацию относительно переменных состояния сервера. Их содержание соответствует информации, произведенной инструкциями SHOW GLOBAL STATUS и SHOW SESSION STATUS.

    INFORMATION_SCHEMA Nmysqlpro/spat.htm 600 0 0 244303 10643273136 7437 Глава 4. Пространственные расширения

    Глава 4. Пространственные расширения

    MySQL поддерживает пространственные расширения, чтобы позволить хранение и анализ географических свойств. Эти свойства доступны для таблиц типов MyISAM, InnoDB, NDB и ARCHIVE. Однако, тип ARCHIVE не поддерживает индексацию, так что пространственные столбцы в столбцах ARCHIVE не могут быть индексированы. MySQL Cluster также не поддерживает индексацию пространственных столбцов.

    Хотя пространственные расширения обеспечиваются в таблицах InnoDB, использование пространственных индексов может вызывать аварийный отказ (Глюк #15860).

    Эта глава покрывает следующие темы:

    • Основание этих пространственных расширений в модели геометрии OpenGIS.

    • Форматы для представления пространственных данных.

    • Как использовать пространственные данные в MySQL.

    • Использование индексации для пространственных данных.

    • Отличия MySQL от спецификации OpenGIS.

    Дополнительные ресурсы

    • Open Geospatial Consortium издает OpenGIS Simple Features Specifications For SQL, документ, который предлагает несколько концептуальных способов для распространения SQL RDBMS, чтобы поддерживать пространственные данные. Эта спецификация доступна на http://www.opengis.org/docs/99-049.pdf.

    • Если Вы имеете вопросы или интересы относительно использования пространственных расширений MySQL, Вы можете обсуждать их на форуме GIS: http://forums.mysql.com/list.php?23.

    4.1. Введение в пространственную поддержку MySQL

    MySQL осуществляет пространственные расширения по спецификации Open Geospatial Consortium (OGC). Это международный консорциум более, чем 250 компаний, агентств и университетов, участвующих в разработке публично доступных концептуальных решений, которые могут быть полезны со всеми видами прикладных программ, которые управляют пространственными данными. OGC поддерживает Web-сайт http://www.opengis.org/.

    В 1997 Open Geospatial Consortium опубликовал OpenGIS Simple Features Specifications For SQL. Эта спецификация доступна на http://www.opengis.org/docs/99-049.pdf.

    MySQL осуществляет подмножество типов SQL with Geometry Types, среду, предложенную OGC. Этот термин относится к SQL-среде, которая была расширена с набором типов геометрии. Оцененный геометрией SQL столбец выполнен как столбец, который имеет тип геометрии. Спецификация описывает набор SQL-типов геометрии также, как функций на этих типах, чтобы создавать и анализировать значения геометрии.

    Географическее свойство состоит в том, что есть что-нибудь в мире, имеющее расположение. Свойство может быть:

    • Объект. Например, гора, водоем, город.

    • Пустота. Например, область почтового индекса, тропики.

    • Определимое расположение. Например, дорога, как специфическое место, где два прохода пересекаются.

    Некоторые документы используют термин geospatial feature, чтобы обратиться к географическим свойствам.

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

    Эта глава использует все эти условия синонимично: geographic feature, geospatial feature, feature или geometry. Обычно используется геометрия, определенная как отметка или набор пунктов (точек), представляющих что-нибудь в мире, что имеет расположение.

    4.2. Модель геометрии OpenGIS

    Набор типов геометрии, предложенных окружением OGC SQL with Geometry Types основан на OpenGIS Geometry Model. В этой модели каждый геометрический объект имеет следующие общие реквизиты:

    • Это связано с пространственной системой ссылки, которая описывает координаты места, в котором объект определен.

    • Это принадлежит некоторому классу геометрии.

    4.2.1. Иерархия класса геометрии

    Классы геометрии определяют свою иерархию следующим образом:

    • Geometry (non-instantiable)

      • Point (instantiable)

      • Curve (non-instantiable)

        • LineString (instantiable)

          • Line

          • LinearRing

      • Surface (non-instantiable)

        • Polygon (instantiable)

      • GeometryCollection (instantiable)

        • MultiPoint (instantiable)

        • MultiCurve (non-instantiable)

          • MultiLineString (instantiable)

        • MultiSurface (non-instantiable)

          • MultiPolygon (instantiable)

    Невозможно создать объекты в non-instantiable классах. Возможно создать объекты в классах instantiable. Все классы имеют реквизиты, и классы instantiable могут также иметь утверждения (правила, которые определяют допустимые образцы класса).

    Geometry базовый класс. Это абстрактный класс. Подклассы Geometry ограничены нуль-, одно- и двумерными геометрическими объектами, которые существуют в двумерном координатном пространстве. Все instantiable классы геометрии определены так, чтобы допустимые образцы класса были закрытой топологии (то есть, все определенные конфигурации включают их границу).

    Основной класс Geometry имеет подклассы для Point, Curve, Surface и GeometryCollection:

    • Point представляет нуль-мерные объекты.

    • Curve представляет одномерные объекты и имеет подкласс LineString с под-подклассами Line и LinearRing.

    • Surface разработан для двумерных объектов и имеет подкласс Polygon.

    • GeometryCollection имеет специальные коллекции для нуль-, одно- и двумерных объектов, известные как MultiPoint, MultiLineString и MultiPolygon для конфигураций моделирования, соответствующих совокупностям Points, LineStrings и Polygons, соответственно. MultiCurve и MultiSurface представляются как абстрактные суперклассы, которые обобщают интерфейсы совокупности, чтобы обработать Curves и Surfaces.

    Geometry, Curve, Surface, MultiCurve и MultiSurface определены как non-instantiable классы. Они определяют общий набор методов для их подклассов и включены для расширяемости.

    Point, LineString, Polygon, GeometryCollection, MultiPoint, MultiLineString и MultiPolygon instantiable классы.

    4.2.2. Класс Geometry

    Geometry представляет собой корневой класс иерархии. Это non-instantiable класс, но имеет ряд реквизитов, которые являются общими для всех значении геометрии, созданных любым из подклассов Geometry. Эти реквизиты описаны в следующем списке. Специфические подклассы имеют их собственные специфические реквизиты, описанные позже.

    Реквизиты геометрии

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

    • type. Каждая геометрия принадлежит одному из instantiable классов в иерархии.

    • SRID или Spatial Reference Identifier (пространственный идентификатор ссылки). Это значение идентифицирует связанную пространственную систему ссылки геометрии, которая описывает координатное пространство, в котором объект геометрии определен. В MySQL значение SRID только целое число, связанное со значением геометрии. Все вычисления выполнены, принимая Евклидову (плоскую) геометрию.

    • Координата в пространственной системе ссылки, представляемая как числа двойной точности (с восьмью байтами). Все не пустые конфигурации включают по крайней мере одну пару координат (X,Y). Пустые конфигурации не содержат никаких координат.

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

    • Внутренний, граничный и внешний.

      Каждая геометрия занимает некоторую позицию. Внешнее, с точки зрения геометрии, это все место, не занятое геометрией. Внутреннее, соответственно, место, занятое геометрией. Граница находится между внутренним и внешним.

    • MBR (Minimum Bounding Rectangle) или Envelope (минимальный ограничительный прямоугольник, конверт). Это геометрия ограничения, сформированная минимумом и максимумом (X,Y):

      ((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))
      
    • Является ли значение простым или нет. Значения геометрии типов (LineString, MultiPoint, MultiLineString) являются простыми или не простыми. Каждый тип определяет собственные утверждения, будучи простым или не простым.

    • Закрыто ли значение или нет. Значения геометрии типов (LineString, MultiString) закрыты или не закрыты. Каждый тип определяет собственные утверждения.

    • Является ли значение пустым или не пустым: геометрия пуста, если не имеет никаких точек. Внешний, внутренний и граница пустой геометрии не определены (то есть они представляются значением NULL). Пустая геометрия определена, чтобы быть всегда простой и имеет область 0.

    • Размерность. Геометрия может иметь размерность 0, 1 или 2:

      • 0 для геометрии без длины и никакой области.

      • 1 для геометрии с ненулевой длиной и нулевой областью, а также для пустой геометрии.

      • 2 для геометрии с ненулевой областью.

      Объекты Point имеют размерность 0. Объекты LineString имеют размерность 1. Объекты Polygon имеют размерность 2. Размерности объектов MultiPoint, MultiLineString и MultiPolygon такие же, как размерности тех элементов, из которых они состоят.

    4.2.3. Класс Point

    Point геометрия, которая представляет одиночное расположение в координатном пространстве.

    Примеры Point

    • Вообразите крупномасштабную карту мира с многими городами. Объект Point мог бы представлять каждый город.

    • На городской карте объект Point мог бы представлять автобусную остановку (Stylus советует "bus stop" писать как "останов шины", зараза с русскими программистами).

    Свойства Point

    • Значение X.

    • Значение Y.

    • Point определена как нуль-мерная геометрия.

    • Границей Point является пустой набор.

    4.2.4. Класс Curve

    Curve одномерная геометрия, обычно представляемая последовательностью точек. Специфические подклассы Curve определяют тип интерполяции между пунктами (точками). Curve non-instantiable.

    Свойства Curve

    • Curve имеет координаты пунктов.

    • Curve определена как одномерная геометрия.

    • Curve проста, если не проходит через ту же самую отметку дважды.

    • Curve закрыта, если отметка начала равна оконечной точке.

    • Граница закрытой Curve пуста.

    • Граница не закрытой Curve состоит из двух оконечных точек.

    • Curve, которая является простой и закрытой, LinearRing.

    4.2.5. Класс LineString

    LineString это Curve с линейной интерполяцией между пунктами (точками).

    Примеры LineString:

    • На всемирной карте объекты LineString могли бы представлять реки.

    • В городской карте объекты LineString могли бы представлять любые проходы.

    Свойства LineString

    • LineString имеет координаты сегментов, определенных каждой последовательной парой пунктов.

    • LineString является Line, если это состоит из точно двух пунктов.

    • LineString является LinearRing, если закрыта и проста.

    4.2.6. Класс Surface

    Surface двумерная геометрия. Это non-instantiable класс. Есть instantiable подкласс: Polygon.

    Свойства Surface

    • Surface определен как двумерная геометрия.

    • OpenGIS определяет простой Surface как геометрию, которая состоит из одиночной заплаты, связанной с одной внешней границей и нулем или более внутренними границами.

    • Граница простого Surface представляет собой набор закрытых кривых, соответствующих внешним и внутренним границам.

    4.2.7. Класс Polygon

    Polygon плоский вариант Surface, представляющий многостороннюю геометрию. Это определено одиночной внешней границей и нулем или более внутренними границами, где каждая внутренняя граница определяет отверстие в Polygon.

    Пример Polygon.

    • На карте области объекты Polygon могли бы представлять леса, районы и так далее.

    Утверждения Polygon.

    • Граница Polygon состоит из набора объектов LinearRing (то есть, объектов LineString, которые являются простыми и закрытыми), которые составляют внешние и внутренние границы.

    • Polygon не имеет никаких пересечений. Кольца в границе Polygon могут пересекаться в Point, но только как тангенс.

    • Polygon не имеет никаких строк, выбросов или проколов.

    • Polygon имеет внутреннюю структуру, которая является связанным набором отметок.

    • Polygon может иметь отверстия. Внешний Polygon с отверстиями не связан. Каждое отверстие определяет связанный компонент внешних.

    Предшествующие утверждения делают Polygon простой геометрией.

    4.2.8. Класс GeometryCollection

    GeometryCollection геометрия, которая является совокупностью одной или большего количества конфигураций любого класса.

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

    • Тип элемента (например, MultiPoint может содержать только элементы Point).

    • Размерность.

    • Ограничения на степень пространственного перекрытия между элементами.

    4.2.9. Класс MultiPoint

    MultiPoint совокупность геометрии, составленная из элементов Point. Пункты (точки) всегда не связаны или упорядочены.

    Примеры MultiPoint:

    • На всемирной карте MultiPoint мог бы представлять цепочку маленьких изолированных островов.

    • На городской карте MultiPoint мог бы представлять выходы.

    Свойства MultiPoint

    • MultiPoint нульмерная геометрия.

    • MultiPoint прост, если никакие два из значений Point не равны (имеют идентичные координатные значения).

    • Граница MultiPoint пустой набор.

    4.2.10. Класс MultiCurve

    MultiCurve совокупность геометрии, составленная из элементов Curve. MultiCurve non-instantiable класс.

    Свойства MultiCurve

    • MultiCurve одномерная геометрия.

    • MultiCurve проста, если (и только если) все элементы просты. Единственные пересечения между любыми двумя элементами происходят в пунктах (точках), которые находятся на границах обоих элементов.

    • Граница MultiCurve получена, применяя правило mod 2 union (также известно как правило odd-even): точка находится в границе MultiCurve, если она находится в границах нечетного числа элементов MultiCurve.

    • MultiCurve закрыта, если все элементы закрыты.

    • Граница закрытой MultiCurve всегда пуста.

    4.2.11. Класс MultiLineString

    MultiLineString совокупность геометрии MultiCurve, составленная из элементов LineString.

    Примеры MultiLineString

    • На карте области MultiLineString мог бы представлять систему рек или систему дорог.

    4.2.12. Класс MultiSurface

    MultiSurface совокупность геометрии, составленная из поверхностных элементов. MultiSurface non-instantiable класс. Есть только instantiable подкласс MultiPolygon.

    Утверждения MultiSurface

    • Две поверхности MultiSurface не имеют никаких внутренностей, которые пересекаются.

    • Два элемента MultiSurface имеют границы, которые пересекаются в конечном числе пунктов (точек).

    4.2.13. Класс MultiPolygon

    MultiPolygon объект MultiSurface, составленный из элементов Polygon.

    Примеры MultiPolygon

    • На карте области MultiPolygon мог бы представлять систему озер.

    Утверждения MultiPolygon

    • MultiPolygon не имеет никаких двух элементов Polygon с внутренностями, которые пересекаются.

    • MultiPolygon не имеет никаких двух элементов Polygon, которые пересекаются (пересечение также запрещается предыдущим утверждением), или же касаются в бесконечном числе (точек).

    • MultiPolygon, возможно, имеет вырезы, выбросы или проколы. MultiPolygon регулярен, закрытый набор отметок.

    • MultiPolygon, который имеет больше чем один Polygon, имеет внутренности, которые не связаны. Число связанных внутренних компонентов MultiPolygon равно числу значений Polygon в MultiPolygon.

    Свойства MultiPolygon

    • MultiPolygon двумерная геометрия.

    • Граница MultiPolygon набор закрытых кривых (значения LineString), соответствующих границам элементов Polygon.

    • Каждая Curve в границе MultiPolygon находится в границе точно одного элемента Polygon.

    • Каждая Curve в границе элемента Polygon находится в границе MultiPolygon.

    4.3. Обеспечиваемые пространственные форматы данных

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

    • Well-Known Text (WKT).

    • Well-Known Binary (WKB).

    Внутренне MySQL сохраняет значения геометрии в формате, который не идентичен любому формату WKT или WKB.

    4.3.1. Well-Known Text (WKT)

    Представление геометрии Well-Known Text (WKT) разработано, чтобы обмениваться данными геометрии в форме ASCII.

    Примеры WKT представлений объектов геометрии:

    • Point:

      POINT(15 20)
      

      Обратите внимание, что отметка определена без отделения запятой.

    • LineString с четырьмя пунктами:

      LINESTRING(0 0, 10 10, 20 25, 50 60)
      

      Обратите внимание, что пары координат отделяются запятыми.

    • Polygon с одним внешним кольцом и одним внутренним кольцом:

      POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))
      
    • MultiPoint с тремя значениями Point:

      MULTIPOINT(0 0, 20 20, 60 60)
      
    • MultiLineString с двумя значениями LineString:

      MULTILINESTRING((10 10, 20 20), (15 15, 30 15))
      
    • MultiPolygon с двумя значениями Polygon:

      MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)),((5 5,7 5,7 7,5 7, 5 5)))
      
    • GeometryCollection, состоящий из двух значений Point и одного LineString:

      GEOMETRYCOLLECTION(POINT(10 10), POINT(30 30), LINESTRING(15 15, 20 20))
      

    Грамматика Backus-Naur, которая определяет формальные правила вывода для записи значений WKT, может быть найдена в спецификации OpenGIS.

    4.3.2. Well-Known Binary (WKB)

    Представление геометрии Well-Known Binary (WKB) определено спецификацией OpenGIS. Это также определено в ISO SQL/MM Part 3: Spatial standard.

    WKB используется, чтобы обмениваться данными геометрии как двоичными потоками, представляемыми значениями BLOB, содержащими геометрическую информацию WKB.

    WKB использует однобайтовые целые числа без знака, целые числа без знака с четырьмя байтами и числа двойной точности с восемью байтами (IEEE 754). Байт равен восьми битам.

    Например, значение WKB, которое соответствует POINT(1 1) состоит из этой последовательности 21 байтов (каждый представляется здесь двумя шестнадцатеричными цифрами):

    0101000000000000000000F03F000000000000F03F
    

    Последовательность может быть разделена на эти компоненты:

    Byte order : 01
    WKB type : 01000000
    X: 000000000000F03F
    Y: 000000000000F03F
    

    Представление компонента следующее:

    • Byte order может быть 0 или 1, чтобы указать little-endian или big-endian формат хранения. little-endian и big-endian также известны как Network Data Representation (NDR) и External Data Representation (XDR), соответственно.

    • WKB type задает код, который указывает тип геометрии. Значения от 1 до 7 указывают Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon и GeometryCollection.

    • Значение Point имеет координаты X и Y, каждпя представляемая как значение двойной точности.

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

    4.4. Создание пространственной базы данных MySQL

    Этот раздел описывает типы данных, которые Вы можете использовать для представления пространственных данных в MySQL и функции, доступные для создания и поиска пространственных значений.

    4.4.1. Пространственные типы данных в MySQL

    MySQL имеет типы данных, которые соответствуют классам OpenGIS. Часть этих типов хранит одиночные значения геометрии:

    • GEOMETRY

    • POINT

    • LINESTRING

    • POLYGON

    GEOMETRY может сохранять значения геометрии любого типа. Другие типы с одиночным значением (POINT, LINESTRING и POLYGON) ограничивают их значения специфическим типом геометрии.

    Другие типы данных хранят совокупности значений:

    • MULTIPOINT

    • MULTILINESTRING

    • MULTIPOLYGON

    • GEOMETRYCOLLECTION

    GEOMETRYCOLLECTION может сохранять совокупность объектов любого типа. Другие типы совокупности (MULTIPOINT, MULTILINESTRING, MULTIPOLYGON и GEOMETRYCOLLECTION) ограничивают элементы совокупности имеющими специфический тип геометрии.

    4.4.2. Создание пространственных значений

    Этот раздел описывает, как создать пространственные значения, использующие функции Well-Known Text и Well-Known Binary, которые определены в стандарте OpenGIS, и применить MySQL-функции.

    4.4.2.1. Создание значений геометрии через функции WKT

    MySQL обеспечивает ряд функций, которые берут как входные параметры представление Well-Known Text и, факультативно, пространственный идентификатор системы ссылки (SRID). Они возвращают соответствующую геометрию.

    GeomFromText() принимает WKT любого типа геометрии как первый параметр. Реализация также обеспечивает специфические для типа функции для конструкции значений геометрии каждого типа.

    • GeomCollFromText(wkt[,srid]), GeometryCollectionFromText(wkt[,srid])

      Создает значение GEOMETRYCOLLECTION, использующее WKT представление и SRID.

    • GeomFromText(wkt[,srid]), GeometryFromText(wkt[,srid])

      Создает значение геометрии из любого типа, использующего WKT представление и SRID.

    • LineFromText(wkt[,srid]), LineStringFromText(wkt[,srid])

      Создает значение LINESTRING, использующее WKT представление и SRID.

    • MLineFromText(wkt[,srid]), MultiLineStringFromText(wkt[,srid])

      Создает значение MULTILINESTRING, использующее WKT представление и SRID.

    • MPointFromText(wkt[,srid]), MultiPointFromText(wkt[,srid])

      Создает значение MULTIPOINT, использующее WKT представление и SRID.

    • MPolyFromText(wkt[,srid]), MultiPolygonFromText(wkt[,srid])

      Создает значение MULTIPOLYGON, использующее WKT представление и SRID.

    • PointFromText(wkt[,srid])

      Создает значение POINT, использующее WKT представление и SRID.

    • PolyFromText(wkt[,srid]), PolygonFromText(wkt[,srid])

      Создает значение POLYGON, использующее WKT представление и SRID.

    Спецификация OpenGIS также определяет следующие факультативные функции, которые MySQL не выполняет. Эти функции создают значения Polygon или MultiPolygon, основанные на WKT представлении совокупности колец или закрытых значений LineString. Эти значения могут пересекаться.

    • BdMPolyFromText(wkt,srid)

      Создает значение MultiPolygon из MultiLineString в формате WKT, содержащем произвольную совокупность закрытых значений LineString.

    • BdPolyFromText(wkt,srid)

      Создает значение Polygon из MultiLineString в формате WKT, содержащем произвольную совокупность закрытых значенийLineString.

    4.4.2.2. Создание значенией геометрии с помощью функций WKB

    MySQL обеспечивает ряд функций, которые берут как входные параметры BLOB, содержащий представление Well-Known Binary и, факультативно, пространственный идентификатор системы ссылки (SRID). Они возвращают соответствующую геометрию.

    GeomFromWKB() принимает WKB любого типа геометрии как первый параметр. Реализация также обеспечивает специфические для типа функции для конструкции значений геометрии каждого типа геометрии.

    • GeomCollFromWKB(wkb[,srid]), GeometryCollectionFromWKB(wkb[,srid])

      Создает значение GEOMETRYCOLLECTION, использующее WKB представление и SRID.

    • GeomFromWKB(wkb[,srid]), GeometryFromWKB(wkb[,srid])

      Создает значение геометрии из любого типа, использующего WKB представление и SRID.

    • LineFromWKB(wkb[,srid]), LineStringFromWKB(wkb[,srid])

      Создает значение LINESTRING, использующее WKB представление и SRID.

    • MLineFromWKB(wkb[,srid]), MultiLineStringFromWKB(wkb[,srid])

      Создает значение MULTILINESTRING, использующее WKB представление и SRID.

    • MPointFromWKB(wkb[,srid]), MultiPointFromWKB(wkb[,srid])

      Создает значение MULTIPOINT, использующее WKB представление и SRID.

    • MPolyFromWKB(wkb[,srid]), MultiPolygonFromWKB(wkb[,srid])

      Создает значение MULTIPOLYGON, использующее WKB представление и SRID.

    • PointFromWKB(wkb[,srid])

      Создает значение POINT, использующее WKB представление и SRID.

    • PolyFromWKB(wkb[,srid]), PolygonFromWKB(wkb[,srid])

      Создает значение POLYGON, использующее WKB представление и SRID.

    Спецификация OpenGIS также описывает факультативные функции для построения значений Polygon или MultiPolygon, основанных на WKB представлении совокупности колец или закрытых значений LineString. Эти значения могут пересекаться. MySQL не выполняет эти функции:

    • BdMPolyFromWKB(wkb,srid)

      Создает значение MultiPolygon из значения MultiLineString в формате WKB, содержащем произвольную совокупность закрытых значений LineString.

    • BdPolyFromWKB(wkb,srid)

      Создает значение Polygon из значения MultiLineString в формате WKB, содержащем произвольную совокупность закрытых значений LineString.

    4.4.2.3. Создание геометрии с использованием MySQL-специфических функций

    MySQL обеспечивает набор полезных ненормативных функций для создания геометрии с WKB представлениями. Функции, описанные в этом разделе, MySQL-расширения спецификации OpenGIS. Результатами этих функций будут значения BLOB, содержащие WKB-представления значений геометрии без SRID. Результаты этих функций могут заменяться как первый параметр любой функции в функциональном семействе GeomFromWKB().

    • GeometryCollection(g1,g2,...)

      Создает значение WKB GeometryCollection. Если параметры не задают правильно построенное WKB представление геометрии, возвращаемое значение NULL.

    • LineString(pt1,pt2,...)

      Создает значение WKB LineString из ряда WKB параметров Point. Если любой аргумент не задает правильный WKB Point, вернется NULL. Если число параметров Point меньше чем два, возвращаемое значение NULL.

    • MultiLineString(ls1,ls2,...)

      Создает значение WKB MultiLineString, использующее WKB параметры LineString. Если любой параметр не WKB LineString, возвращаемое значение NULL.

    • MultiPoint(pt1,pt2,...)

      Создает значение WKB MultiPoint, использующее WKB параметры Point. Если любой параметр не WKB Point, возвращаемое значение NULL.

    • MultiPolygon(poly1,poly2,...)

      Создает значение WKB MultiPolygon из набора WKB параметров Polygon. Если любой параметр не WKB Polygon, возвращаемое значение NULL.

    • Point(x,y)

      Создает значение WKB Point, используя координаты.

    • Polygon(ls1,ls2,...)

      Создает значение WKB Polygon из ряда WKB параметров LineString. Если любой параметр не представляет WKB LinearRing (то есть не закрытый и простой LineString), возвращаемое значение NULL.

    4.4.3. Создание пространственных столбцов

    MySQL обеспечивает стандартный способ создания пространственных столбцов для типов геометрии, например, через CREATE TABLE или ALTER TABLE. В настоящее время пространственные столбцы обеспечиваются для таблиц типов MyISAM, InnoDB, NDB и ARCHIVE.

    • Используйте инструкцию CREATE TABLE, чтобы создать таблицу с пространственным столбцом:

      CREATE TABLE geom (g GEOMETRY);
      
    • Используйте инструкцию ALTER TABLE, чтобы добавлять или удалять пространственный столбец в существующей таблице:

      ALTER TABLE geom ADD pt POINT;
      ALTER TABLE geom DROP pt;
      

    4.4.4. Начальная загрузка пространственных столбцов

    После того, как Вы создали пространственные столбцы, Вы можете заполнять их пространственными данными.

    Значения должны быть сохранены во внутреннем формате геометрии, но Вы можете преобразовывать их в этот формат из Well-Known Text (WKT) или из Well-Known Binary (WKB). Следующие примеры показывают, как вставить значения геометрии в таблицу, преобразуя значения WKT во внутренний формат геометрии:

    • Выполните преобразование непосредственно в инструкции INSERT:

      INSERT INTO geom VALUES (GeomFromText('POINT(1 1)'));
      SET @g = 'POINT(1 1)';
      INSERT INTO geom VALUES (GeomFromText(@g));
      
    • Выполните преобразование до INSERT:

      SET @g = GeomFromText('POINT(1 1)');
      INSERT INTO geom VALUES (@g);
      

    Следующие примеры вставляют более сложные конфигурации в таблицу:

    SET @g = 'LINESTRING(0 0,1 1,2 2)';
    INSERT INTO geom VALUES (GeomFromText(@g));
    SET @g = 'POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))';
    INSERT INTO geom VALUES (GeomFromText(@g));
    SET @g = 'GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))';
    INSERT INTO geom VALUES (GeomFromText(@g));
    

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

    SET @g = 'POINT(1 1)';
    INSERT INTO geom VALUES (PointFromText(@g));
    SET @g = 'LINESTRING(0 0,1 1,2 2)';
    INSERT INTO geom VALUES (LineStringFromText(@g));
    SET @g = 'POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))';
    INSERT INTO geom VALUES (PolygonFromText(@g));
    SET @g = 'GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))';
    INSERT INTO geom VALUES (GeomCollFromText(@g));
    

    Обратите внимание, что, если прикладная программа пользователя хочет использовать WKB-представления значений геометрии, она ответственна за посылку правильно сформированных WKB в запросах на сервер. Однако, имеются несколько способов удовлетворения этого требования. Например:

    • Вставка значения POINT(1 1) с шестнадцатеричным литеральным синтаксисом:

      mysql> INSERT INTO geom VALUES
          -> (GeomFromWKB(0x0101000000000000000000F03F000000000000F03F));
      
    • ODBC-прикладная программа может посылать WKB-представление, привязывая его к метке-заполнителю, использующей параметр типа BLOB:

      INSERT INTO geom VALUES (GeomFromWKB(?))
      

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

    • В программе на C Вы можете выходить из двоичного значения, используя mysql_real_escape_string() и включать результат в строку запроса, которая послана серверу.

    4.4.5. Выборка пространственных данных

    Значения геометрии, сохраненные в таблице, могут быть выбраны во внутреннем формате. Вы можете также преобразовывать их в формат WKT или WKB.

    • Выборка пространственных данных во внутреннем формате:

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

      CREATE TABLE geom2 (g GEOMETRY) SELECT g FROM geom;
      
    • Выборка пространственных данных в формате WKT:

      Функция AsText() преобразовывает геометрию из внутреннего формата в строку WKT.

      SELECT AsText(g) FROM geom;
      
    • Выборка пространственных данных в формате WKB:

      Функция AsBinary() преобразовывает геометрию из внутреннего формата в BLOB WKB.

      SELECT AsBinary(g) FROM geom;
      

    4.5. Анализ пространственной информации

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

    • Функции, которые преобразовывают конфигурации между различными форматами.

    • Функции, которые обеспечивают доступ к качественным или количественным реквизитам геометрии.

    • Функции, которые описывают отношения между двумя конфигурациями.

    • Функции, которые создают новые конфигурации из существующих.

    Пространственные функции анализа могут использоваться во многих контекстах, типа:

    • Любая интерактивная программа SQL, типа mysql или MySQL Query Browser.

    • Прикладные программы, написанные на любом языке, который поддерживает клиентский MySQL API.

    4.5.1. Функции преобразования формата геометрии

    MySQL поддерживает следующие функции для преобразования значений геометрии между внутренним форматом и форматом WKT или WKB:

    • AsBinary(g)

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

      SELECT AsBinary(g) FROM geom;
      
    • AsText(g)

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

      mysql> SET @g = 'LineString(1 1,2 2,3 3)';
      mysql> SELECT AsText(GeomFromText(@g));
      +--------------------------+
      | AsText(GeomFromText(@g)) |
      +--------------------------+
      | LINESTRING(1 1,2 2,3 3)  |
      +--------------------------+
      
    • GeomFromText(wkt[,srid])

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

    • GeomFromWKB(wkb[,srid])

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

    Функции 4.5.2. Geometry

    Каждая функция, которая принадлежит к этой группе, берет значение геометрии как параметр и возвращает некоторое количественное или качественное свойство геометрии. Некоторые функции ограничивают их тип параметра. Такие функции возвращают NULL, если параметр имеет неправильный тип геометрии. Например, Area() возвращает NULL, если тип объекта не является ни Polygon, ни MultiPolygon.

    4.5.2.1. Общие функции геометрии

    Функции, перечисленные в этом разделе, не ограничивают их параметр и принимают значение геометрии любого типа.

    • Dimension(g)

      Возвращается свойственная размерность геометрии g. Результат может быть 0, 1 или 2. Смысл этих значений дан в разделе " 4.2.2. Класс Geometry".

      mysql> SELECT Dimension(GeomFromText('LineString(1 1,2 2)'));
      +------------------------------------------------+
      | Dimension(GeomFromText('LineString(1 1,2 2)')) |
      +------------------------------------------------+
      | 1                                              |
      +------------------------------------------------+
      
    • Envelope(g)

      Возвращается минимальный ограничительный прямоугольник (MBR) для геометрии g. Результат возвращен как значение Polygon.

      Многоугольник определен пунктами (точками) угла блока ограничения:

      POLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))
      mysql> SELECT AsText(Envelope(GeomFromText('LineString(1 1,2 2)')));
      +-------------------------------------------------------+
      | AsText(Envelope(GeomFromText('LineString(1 1,2 2)'))) |
      +-------------------------------------------------------+
      | POLYGON((1 1,2 1,2 2,1 2,1 1))                        |
      +-------------------------------------------------------+
      
    • GeometryType(g)

      Возвращает как строку имя типа геометрии, образец которой является членом g. Имя соответствует одному из instantiable подклассов Geometry.

      mysql> SELECT GeometryType(GeomFromText('POINT(1 1)'));
      +------------------------------------------+
      | GeometryType(GeomFromText('POINT(1 1)')) |
      +------------------------------------------+
      | POINT                                    |
      +------------------------------------------+
      
    • SRID(g)

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

      В MySQL значение SRID только целое число, связанное со значением геометрии. Все вычисления выполнены, принимая евклидову (плоскую) геометрию.

      mysql> SELECT SRID(GeomFromText('LineString(1 1,2 2)',101));
      +-----------------------------------------------+
      | SRID(GeomFromText('LineString(1 1,2 2)',101)) |
      +-----------------------------------------------+
      | 101                                           |
      +-----------------------------------------------+
      

    Спецификация OpenGIS также определяет следующие функции, которые MySQL не выполняет:

    • Boundary(g)

      Возвращает геометрию, которая является замкнутым выражением комбинаторной границы геометрии g.

    • IsEmpty(g)

      Возвращается 1, если геометрия g пустая геометрия, 0, если это не пусто, и 1, если параметр NULL. Если геометрия пуста, это представляет пустой набор точек.

    • IsSimple(g)

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

      Возвращается 1, если геометрия g не имеет никаких аномальных геометрических пунктов (точек), типа самопересечения или самокасания. IsSimple() возвращает 0, если параметр не прост, и 1, если он NULL.

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

    4.5.2.2. Функции Point

    Point состоит из координат X и Y, которые могут быть получены, используя следующие функции:

    • X(p)

      Возвращает значение X-координаты для p как число двойной точности.

      mysql> SET @pt = 'Point(56.7 53.34)';
      mysql> SELECT X(GeomFromText(@pt));
      +----------------------+
      | X(GeomFromText(@pt)) |
      +----------------------+
      | 56.7                 |
      +----------------------+
      
    • Y(p)

      Возвращает значение Y-координаты для p как число двойной точности.

      mysql> SET @pt = 'Point(56.7 53.34)';
      mysql> SELECT Y(GeomFromText(@pt));
      +----------------------+
      | Y(GeomFromText(@pt)) |
      +----------------------+
      | 53.34                |
      +----------------------+
      

    4.5.2.3. Функции LineString

    LineString состоит из значений Point. Вы можете извлекать специфические пункты (точки) LineString, считать число точек объекта или получать длину.

    • EndPoint(ls)

      Возвращает Point, которая является оконечной точкой значения LineString ls.

      mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
      mysql> SELECT AsText(EndPoint(GeomFromText(@ls)));
      +-------------------------------------+
      | AsText(EndPoint(GeomFromText(@ls))) |
      +-------------------------------------+
      | POINT(3 3)                          |
      +-------------------------------------+
      
    • GLength(ls)

      Возвращает как число двойной точности длина значение LineString ls в связанной пространственной ссылке.

      mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
      mysql> SELECT GLength(GeomFromText(@ls));
      +----------------------------+
      | GLength(GeomFromText(@ls)) |
      +----------------------------+
      | 2.8284271247462            |
      +----------------------------+
      

      GLength() ненормативное имя. Это передает данные функции OpenGIS Length().

    • NumPoints(ls)

      Возвращает число объектов Point в the LineString ls.

      mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
      mysql> SELECT NumPoints(GeomFromText(@ls));
      +------------------------------+
      | NumPoints(GeomFromText(@ls)) |
      +------------------------------+
      | 3                            |
      +------------------------------+
      
    • PointN(ls,N)

      Возвращает N-ый Point в Linestring ls. Точки пронумерованы, начиная с 1.

      mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
      mysql> SELECT AsText(PointN(GeomFromText(@ls),2));
      +-------------------------------------+
      | AsText(PointN(GeomFromText(@ls),2)) |
      +-------------------------------------+
      | POINT(2 2)                          |
      +-------------------------------------+
      
    • StartPoint(ls)

      Возвращает Point, которая является отметкой начала значения point of the LineString ls.

      mysql> SET @ls = 'LineString(1 1,2 2,3 3)';
      mysql> SELECT AsText(StartPoint(GeomFromText(@ls)));
      +---------------------------------------+
      | AsText(StartPoint(GeomFromText(@ls))) |
      +---------------------------------------+
      | POINT(1 1)                            |
      +---------------------------------------+
      

    Спецификация OpenGIS также определяет следующую функцию, которую MySQL не выполняет:

    • IsRing(ls)

      Возвращает 1, если значение LineString value ls закрыто (то есть, значения StartPoint() и EndPoint() те же самые) и просто (не проходит через ту же самую точку больше, чем один раз). Возвращается 0, если ls не кольцо, и 1, если это NULL.

    4.5.2.4. Функции MultiLineString

    • GLength(mls)

      Возвращает как число двойной точности длину значения MultiLineString mls. Длина mls равна сумме длин элементов.

      mysql> SET @mls = 'MultiLineString((1 1,2 2,3 3),(4 4,5 5))';
      mysql> SELECT GLength(GeomFromText(@mls));
      +-----------------------------+
      | GLength(GeomFromText(@mls)) |
      +-----------------------------+
      | 4.2426406871193             |
      +-----------------------------+
      

      GLength() ненормативное имя. Это передает данные функции OpenGIS Length().

    • IsClosed(mls)

      Возвращает 1, если значение MultiLineString mls закрыто (то есть, значения StartPoint() и EndPoint() равны для каждого LineString в mls). Возвращает 0, если mls не закрыт, и 1, если это NULL.

      mysql> SET @mls = 'MultiLineString((1 1,2 2,3 3),(4 4,5 5))';
      mysql> SELECT IsClosed(GeomFromText(@mls));
      +------------------------------+
      | IsClosed(GeomFromText(@mls)) |
      +------------------------------+
      | 0                            |
      +------------------------------+
      

    4.5.2.5. Функции Polygon

    • Area(poly)

      Возвращает как число двойной точности область значения Polygon poly, как измеряется в пространственной системе ссылки.

      mysql> SET @poly = 'Polygon((0 0,0 3,3 0,0 0),(1 1,1 2,2 1,1 1))';
      mysql> SELECT Area(GeomFromText(@poly));
      +---------------------------+
      | Area(GeomFromText(@poly)) |
      +---------------------------+
      | 4                         |
      +---------------------------+
      
    • ExteriorRing(poly)

      Возвращает внешнее кольцо значения Polygon poly как LineString.

      mysql> SET @poly = 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';
      mysql> SELECT AsText(ExteriorRing(GeomFromText(@poly)));
      +-------------------------------------------+
      | AsText(ExteriorRing(GeomFromText(@poly))) |
      +-------------------------------------------+
      | LINESTRING(0 0,0 3,3 3,3 0,0 0)           |
      +-------------------------------------------+
      
    • InteriorRingN(poly,N)

      Возвращает N-ное внутреннее кольцо для значения Polygon poly как LineString. Кольца пронумерованы, начиная с 1.

      mysql> SET @poly =
          ->     'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';
      mysql> SELECT AsText(InteriorRingN(GeomFromText(@poly),1));
      +----------------------------------------------+
      | AsText(InteriorRingN(GeomFromText(@poly),1)) |
      +----------------------------------------------+
      | LINESTRING(1 1,1 2,2 2,2 1,1 1)              |
      +----------------------------------------------+
      
    • NumInteriorRings(poly)

      Возвращает число внутренних колец в значении Polygon poly.

      mysql> SET @poly =
          ->     'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';
      mysql> SELECT NumInteriorRings(GeomFromText(@poly));
      +---------------------------------------+
      | NumInteriorRings(GeomFromText(@poly)) |
      +---------------------------------------+
      | 1                                     |
      +---------------------------------------+
      

    4.5.2.6. Функции MultiPolygon

    • Area(mpoly)

      Возвращает как число двойной точности область значения MultiPolygon mpoly, как измеряется в пространственной системе ссылки.

      mysql> SET @mpoly =
          ->     'MultiPolygon(((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1)))';
      mysql> SELECT Area(GeomFromText(@mpoly));
      +----------------------------+
      | Area(GeomFromText(@mpoly)) |
      +----------------------------+
      | 8                          |
      +----------------------------+
      

    Спецификация OpenGIS также определяет следующие функции, которые MySQL не выполняет:

    • Centroid(mpoly)

      Возвращает математический центр для значения MultiPolygon mpoly как Point. Не гарантируется, что результат будет в MultiPolygon.

    • PointOnSurface(mpoly)

      Возвращает значение Point, которое гарантированно будет в значении MultiPolygon mpoly.

    4.5.2.7. Функции GeometryCollection

    • GeometryN(gc,N)

      Возвращает N-ую геометрию в значении GeometryCollection gc. Конфигурации пронумерованы, начиная с 1.

      mysql> SET @gc = 'GeometryCollection(Point(1 1), LineString(2 2, 3 3))';
      mysql> SELECT AsText(GeometryN(GeomFromText(@gc), 1));
      +----------------------------------------+
      | AsText(GeometryN(GeomFromText(@gc), 1))|
      +----------------------------------------+
      | POINT(1 1)                             |
      +----------------------------------------+
      
    • NumGeometries(gc)

      Возвращает число конфигураций в значении GeometryCollection gc.

      mysql> SET @gc = 'GeometryCollection(Point(1 1), LineString(2 2, 3 3))';
      mysql> SELECT NumGeometries(GeomFromText(@gc));
      +----------------------------------+
      | NumGeometries(GeomFromText(@gc)) |
      +----------------------------------+
      | 2                                |
      +----------------------------------+
      

    4.5.3. Функции, которые создают новые конфигурации из существующих

    4.5.3.1. Функции геометрии, которые производят новые конфигурации

    Раздел "4.5.2. Функции Geometry" обсуждает несколько функций, которые создают новые конфигурации из существующих.

    • Envelope(g)

    • StartPoint(ls)

    • EndPoint(ls)

    • PointN(ls,N)

    • ExteriorRing(poly)

    • InteriorRingN(poly,N )

    • GeometryN(gc,N)

    4.5.3.2. Пространственные операторы

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

    Эти функции не выполнены в MySQL. Они могут появляться в будущих выпусках.

    • Buffer(g,d)

      Возвращает геометрию, которая представляет все пункты (точки), чьи расстояния от геометрии g меньше или равны расстоянию d.

    • ConvexHull(g)

      Возвращает геометрию, которая представляет выпуклую оболочку геометрии g.

    • Difference(g1,g2)

      Возвращает геометрию, которая представляет разность множеств точек значения геометрий g1 и g2.

    • Intersection(g1,g2)

      Возвращает геометрию, которая представляет пересечение набора точек геометрий g1 и g2.

    • SymDifference(g1,g2)

      Возвращает геометрию, которая представляет набор точек, симметричных разнице значений геометрий g1 и g2.

    • Union(g1,g2)

      Возвращает геометрию, которая представляет объединение набора точек значений геометрии g1 и g2.

    4.5.4. Функции для тестирования пространственных отношений между геометрическими объектами

    Функции, описанные в этих разделах, берут две конфигурации как входные параметры и возвращают качественное или количественное отношение между ними.

    4.5.5. Отношения на геометрии: минимальные ограничительные прямоугольники (MBR)

    MySQL обеспечивает несколько функций, которые проверяют отношения между минимальными ограничительными прямоугольниками двух конфигураций g1 и g2. Возвращаемые значения 1 и 0 указывают истину и ложь соответственно.

    • MBRContains(g1,g2)

      Возвращает 1 или 0, чтобы указать, содержит ли минимальный ограничительный прямоугольник g1 минимальный ограничительный прямоугольник g2.

      mysql> SET @g1 = GeomFromText('Polygon((0 0, 0 3, 3 3, 3 0, 0 0))');
      mysql> SET @g2 = GeomFromText('Point(1 1)');
      mysql> SELECT MBRContains(@g1, @g2), MBRContains(@g2, @g1);
      +----------------------+----------------------+
      | MBRContains(@g1, @g2)| MBRContains(@g2, @g1)|
      +----------------------+----------------------+
      | 1                    | 0                    |
      +----------------------+----------------------+
      
    • MBRDisjoint(g1,g2)

      Возвращает 1 или 0, чтобы указать, являются ли минимальные ограничительные прямоугольники двух конфигураций g1 и g2 непересекающимися.

    • MBREqual(g1,g2)

      Возвращает 1 или 0, чтобы указать, являются ли минимальные ограничительные прямоугольники двух конфигураций g1 и g2 тем же самым.

    • MBRIntersects(g1,g2)

      Возвращает 1 или 0, чтобы указать, пересекаются ли минимальные ограничительные прямоугольники двух конфигураций g1 и g2.

    • MBROverlaps(g1,g2)

      Возвращает 1 или 0, чтобы указать, накладываются ли минимальные ограничительные прямоугольники g1 и g2.

    • MBRTouches(g1,g2)

      Возвращает 1 или 0, чтобы указать, касаются ли минимальные ограничительные прямоугольники g1 и g2.

    • MBRWithin(g1,g2)

      Возвращает 1 или 0, чтобы указать, является ли минимальный ограничительный прямоугольник g1 внутренним для минимального ограничительного прямоугольника g2.

      mysql> SET @g1 = GeomFromText('Polygon((0 0, 0 3, 3 3, 3 0, 0 0))');
      mysql> SET @g2 = GeomFromText('Polygon((0 0, 0 5, 5 5, 5 0, 0 0))');
      mysql> SELECT MBRWithin(@g1, @g2), MBRWithin(@g2, @g1);
      +--------------------+--------------------+
      | MBRWithin(@g1, @g2)| MBRWithin(@g2, @g1)|
      +--------------------+--------------------+
      | 1                  | 0                  |
      +--------------------+--------------------+
      

    4.5.6. Функции, которые проверяют пространственные связи между конфигурациями

    Спецификация OpenGIS определяет следующие функции. Они проверяют связь между двумя значениями геометрии g1 и g2.

    В настоящее время MySQL не выполняет эти функции согласно спецификации. Которые выполнены, возвратят тот же самый результат, что и соответствующие MBR-функции. Это включает функции в следующем списке. Эти функции могут быть выполнены в будущих выпусках с полной поддержкой для пространственного анализа, а не только MBR-поддержки.

    • Contains(g1,g2)

      Возвращает 1 или 0, чтобы указать, содержит ли g1 полностью g2.

    • Crosses(g1,g2)

      Возвращает 1, если g1 пространственно пересекает g2. Возвращает NULL, если g1 Polygon или MultiPolygon, либо если g2 Point или MultiPoint. Иначе возвращает 0.

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

      • Две конфигурации пересекаются.

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

      • Их пересечение не равно любой из двух данных конфигураций.

    • Disjoint(g1,g2)

      Возвращается 1 или 0, чтобы указать, является ли g1 пространственно непересекающейся с g2.

    • Distance(g1,g2)

      Возвращает как число двойной точности самое короткое расстояние между любыми двумя точками в двух конфигурациях.

    • Equals(g1,g2)

      Возвращает 1 или 0, чтобы указать, является ли g1 пространственно равной g2.

    • Intersects(g1,g2)

      Возвращает 1 или 0, чтобы указать, пересекает ли g1 пространственно g2.

    • Overlaps(g1,g2)

      Возвращает 1 или 0, чтобы указать, накладывается ли g1 пространственно на g2. Термин "пространственно накладывается" используется, если две конфигурации пересекаются, и их пересечение приводит к геометрии той же самой размерности, но не равной любой из данных конфигураций.

    • Related(g1,g2,pattern_matrix )

      Возвращает 1 или 0, чтобы указать, существует ли пространственная связь, определенная pattern_matrix между g1 и g2. Возвращает 1, если параметры NULL. Матрица образцов является строкой. Спецификация будет отмечена здесь, если эта функция выполнена.

    • Touches(g1,g2)

      Возвращается 1 или 0, чтобы указать, касается ли g1 пространственно g2. Две конфигурации пространственно касаются, если внутренности конфигураций не пересекаются, но граница одной из конфигураций пересекает границу или внутренность другой.

    • Within(g1,g2)

      Возвращается 1 или 0, чтобы указать, является ли g1 пространственно внутри g2.

    4.6. Оптимизация пространственного анализа

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

    • Запросы точки, которые ищут все объекты, которые содержат данную точку.

    • Запросы области, которые ищут все объекты, которые накладываются на данную область.

    MySQL использует R-деревья с квадратным разбиением, чтобы индексировать пространственные столбцы. Пространственный индекс сформирован, используя MBR геометрии. Для большинства конфигураций MBR минимальный прямоугольник, который окружает конфигурацию. Для горизонтальных или вертикальных linestring MBR прямоугольник, вырождающийся в linestring. Для point MBR является точкой.

    Также возможно создать нормальные индексы на пространственных столбцах. Вам надо объявить префикс для любого непространственного индекса на пространственном столбце, кроме столбцов POINT.

    4.6.1. Создание пространственных индексов

    MySQL может создавать пространственные индексы, использующие синтаксис, подобный аналогичному для создания регулярных индексов, но расширенный с ключевым словом SPATIAL. В настоящее время пространственные столбцы, которые индексированы, должны быть объявлены как NOT NULL. Следующие примеры показывают, как создавать пространственные индексы:

    • С CREATE TABLE:

      CREATE TABLE geom (g GEOMETRY NOT NULL, SPATIAL INDEX(g));
      
    • С ALTER TABLE:

      ALTER TABLE geom ADD SPATIAL INDEX(g);
      
    • С CREATE INDEX:

      CREATE SPATIAL INDEX sp_index ON geom (g);
      

    Для таблиц MyISAM SPATIAL INDEX создает индекс R-tree. Для других типов памяти, которые поддерживают пространственную индексацию, SPATIAL INDEX создает индекс B-tree. B-tree на пространственных значениях будет полезен для поисковых таблиц с точным значением, но не для диапазона.

    Для удаления пространственного индекса, используйте ALTER TABLE или DROP INDEX:

    • С ALTER TABLE:

      ALTER TABLE geom DROP INDEX g;
      
    • С DROP INDEX:

      DROP INDEX sp_index ON geom;
      

    Пример: Предположите, что таблица geom содержит больше, чем 32000 конфигурации, которые сохранены в столбце g типа GEOMETRY. Таблица также имеет столбец AUTO_INCREMENT fid для сохранения значений объекта ID.

    mysql> DESCRIBE geom;
    +-------+----------+------+-----+---------+----------------+
    | Field | Type     | Null | Key | Default | Extra          |
    +-------+----------+------+-----+---------+----------------+
    | fid   | int(11)  |      | PRI | NULL    | auto_increment |
    | g     | geometry |      |     |         |                |
    +-------+----------+------+-----+---------+----------------+
    2 rows in set (0.00 sec)
    
    mysql> SELECT COUNT(*) FROM geom;
    +----------+
    | count(*) |
    +----------+
    | 32376    |
    +----------+
    1 row in set (0.00 sec)
    

    Чтобы добавлять пространственный индекс на столбце g, используйте эту инструкцию:

    mysql> ALTER TABLE geom ADD SPATIAL INDEX(g);
    Query OK, 32376 rows affected (4.05 sec)
    Records: 32376 Duplicates: 0 Warnings: 0
    

    4.6.2. Использование пространственного индекса

    Оптимизатор исследует, могут ли доступные пространственные индексы включаться в поиск для запросов, которые используют функцию типа MBRContains() или MBRWithin() в предложении WHERE. Следующий запрос находит все объекты, которые находятся в данном прямоугольнике:

    mysql> SET @poly = 'Polygon((30000 15000, 31000 15000, 31000 16000,
        ->                       30000 16000, 30000 15000))';
    mysql> SELECT fid, AsText(g) FROM geom WHERE
        ->        MBRContains(GeomFromText(@poly), g);
    +-----+---------------------------------------------------------------+
    | fid | AsText(g)                                                     |
    +-----+---------------------------------------------------------------+
    |  21 | LINESTRING(30350.4 15828.8,30350.6 15845,30333.8 15845,30 ... |
    |  22 | LINESTRING(30350.6 15871.4,30350.6 15887.8,30334 15887.8, ... |
    |  23 | LINESTRING(30350.6 15914.2,30350.6 15930.4,30334 15930.4, ... |
    |  24 | LINESTRING(30290.2 15823,30290.2 15839.4,30273.4 15839.4, ... |
    |  25 | LINESTRING(30291.4 15866.2,30291.6 15882.4,30274.8 15882. ... |
    |  26 | LINESTRING(30291.6 15918.2,30291.6 15934.4,30275 15934.4, ... |
    | 249 | LINESTRING(30337.8 15938.6,30337.8 15946.8,30320.4 15946. ... |
    |   1 | LINESTRING(30250.4 15129.2,30248.8 15138.4,30238.2 15136. ... |
    |   2 | LINESTRING(30220.2 15122.8,3024.2 15137.8,30207.6 15136, ... |
    |   3 | LINESTRING(30179 15114.4,30176.6 15129.4,30167 15128,3016 ... |
    |   4 | LINESTRING(30155.2 15121.4,30140.4 15118.6,30142 15109,30 ... |
    |   5 | LINESTRING(30192.4 15085,30177.6 15082.2,30179.2 15072.4, ... |
    |   6 | LINESTRING(30244 15087,30229 15086.2,30229.4 15076.4,3024 ... |
    |   7 | LINESTRING(30200.6 15059.4,30185.6 15058.6,30186 15048.8, ... |
    |  10 | LINESTRING(30179.6 1504.8,30181 15002.8,30190.8 15003.6, ... |
    |  11 | LINESTRING(30154.2 15000.4,30168.6 15004.8,30166 15014.2, ... |
    |  13 | LINESTRING(30105 15065.8,30108.4 15050.8,30118 15053,3011 ... |
    | 154 | LINESTRING(30276.2 15143.8,30261.4 15141,30263 15131.4,30 ... |
    | 155 | LINESTRING(30269.8 15084,30269.4 15093.4,30258.6 15093,30 ... |
    | 157 | LINESTRING(30128.2 15011,30113.2 15010.2,30113.6 15000.4, ... |
    +-----+---------------------------------------------------------------+
    20 rows in set (0.00 sec)
    

    Использование EXPLAIN показывает, каким способом этот запрос выполнен:

    mysql> SET @poly = 'Polygon((30000 15000, 31000 15000,
        ->                       31000 16000, 30000 16000, 30000 15000))';
    mysql> EXPLAIN SELECT fid, AsText(g) FROM geom WHERE
        ->         MBRContains(GeomFromText(@poly), g)\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: geom
    type: range
    possible_keys: g
    key: g
    key_len: 32
    ref: NULL
    rows: 50
    Extra: Using where
    1 row in set (0.00 sec)
    

    Проверьте, что случилось бы без пространственного индекса:

    mysql> SET @poly = 'Polygon((30000 15000, 31000 15000,
        ->                       31000 16000, 30000 16000, 30000 15000))';
    mysql> EXPLAIN SELECT fid,AsText(g) FROM g IGNORE INDEX (g) WHERE
        ->         MBRContains(GeomFromText(@poly), g)\G
    *************************** 1. row ***************************
    id: 1
    select_type: SIMPLE
    table: geom
    type: ALL
    possible_keys: NULL
    key: NULL
    key_len: NULL
    ref: NULL
    rows: 32376
    Extra: Using where
    1 row in set (0.00 sec)
    

    Выполнение инструкции SELECT без пространственного индекса выдает тот же самый результат, но заставляет время выполнения повышаться с 0.00 до 0.46 секунды:

    mysql> SET @poly = 'Polygon((30000 15000, 31000 15000,
        ->                       31000 16000, 30000 16000, 30000 15000))';
    mysql> SELECT fid, AsText(g) FROM geom IGNORE INDEX (g) WHERE
        ->        MBRContains(GeomFromText(@poly), g);
    +-----+---------------------------------------------------------------+
    | fid | AsText(g)                                                     |
    +-----+---------------------------------------------------------------+
    |   1 | LINESTRING(30250.4 15129.2,30248.8 15138.4,30238.2 15136. ... |
    |   2 | LINESTRING(30220.2 15122.8,3024.2 15137.8,30207.6 15136, ... |
    |   3 | LINESTRING(30179 15114.4,30176.6 15129.4,30167 15128,3016 ... |
    |   4 | LINESTRING(30155.2 15121.4,30140.4 15118.6,30142 15109,30 ... |
    |   5 | LINESTRING(30192.4 15085,30177.6 15082.2,30179.2 15072.4, ... |
    |   6 | LINESTRING(30244 15087,30229 15086.2,30229.4 15076.4,3024 ... |
    |   7 | LINESTRING(30200.6 15059.4,30185.6 15058.6,30186 15048.8, ... |
    |  10 | LINESTRING(30179.6 1504.8,30181 15002.8,30190.8 15003.6, ... |
    |  11 | LINESTRING(30154.2 15000.4,30168.6 15004.8,30166 15014.2, ... |
    |  13 | LINESTRING(30105 15065.8,30108.4 15050.8,30118 15053,3011 ... |
    |  21 | LINESTRING(30350.4 15828.8,30350.6 15845,30333.8 15845,30 ... |
    |  22 | LINESTRING(30350.6 15871.4,30350.6 15887.8,30334 15887.8, ... |
    |  23 | LINESTRING(30350.6 15914.2,30350.6 15930.4,30334 15930.4, ... |
    |  24 | LINESTRING(30290.2 15823,30290.2 15839.4,30273.4 15839.4, ... |
    |  25 | LINESTRING(30291.4 15866.2,30291.6 15882.4,30274.8 15882. ... |
    |  26 | LINESTRING(30291.6 15918.2,30291.6 15934.4,30275 15934.4, ... |
    | 154 | LINESTRING(30276.2 15143.8,30261.4 15141,30263 15131.4,30 ... |
    | 155 | LINESTRING(30269.8 15084,30269.4 15093.4,30258.6 15093,30 ... |
    | 157 | LINESTRING(30128.2 15011,30113.2 15010.2,30113.6 15000.4, ... |
    | 249 | LINESTRING(30337.8 15938.6,30337.8 15946.8,30320.4 15946. ... |
    +-----+---------------------------------------------------------------+
    20 rows in set (0.46 sec)
    

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

    4.7. MySQL: согласованность и совместимость

    MySQL еще не выполняет следующие свойства GIS:

    • Дополнительные просмотры метаданных.

      Спецификация OpenGIS предлагает несколько дополнительных просмотров метаданных. Например, просмотр системы GEOMETRY_COLUMNS содержит описание столбцов геометрии, одна строка для каждого столбца геометрии в базе данных.

    • Функция OpenGIS Length() на LineString и MultiLineString в настоящее время должна быть вызвана в MySQL как GLength()

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

    ную точку.

  • Запросы области, которые ищут все объекты, которые накладываются на данную область.

  • MySQL использует R-деревья с квадратным разбиением, чтобы индексировать пространственные столбцы. Пространственный индекс сформирован, используя MBR геометрии. Для большинства конфигmysqlpro/sto_proc.htm 600 0 0 215720 10643273262 10321 Глава 5. Сохраненные процедуры и функции

    Глава 5. Сохраненные процедуры и функции

    Сохраненные подпрограммы (процедуры и функции) обеспечиваются в MySQL 5.0. Сохраненная процедура представляет собой набор инструкций SQL, которые могут быть сохранены на сервере. Если это было выполнено, клиентура не должна хранить индивидуальные инструкции, а может обратиться к сохраненной процедуре.

    Некоторые ситуации, где сохраненные подпрограммы могут быть особенно полезны:

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

    • Когда защита первостепенна. Банки, например, используют сохраненные процедуры и функции для всех общих операций. Это обеспечивает непротиворечивую и безопасную среду, и подпрограммы могут гарантировать, что каждая операция правильно регистрируется. В такой установке прикладные программы (и их пользователи!) не имеют никакого доступа к таблицам базы данных непосредственно, а могут только выполнять специфические сохраненные подпрограммы. То есть, при всем желании, не смогут приписать лишний ноль...

    Сохраненные подпрограммы могут обеспечивать улучшенную эффективность, потому что меньшее количество информации должно быть переслано между клиентом и сервером. Правда это увеличивает нагрузку на сервер, поскольку большее количество работы выполнено на сервере. Рассмотрите это, если много машин пользователя (типа Web-серверов) обслуживаются только одним сервером базы данных.

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

    MySQL следует синтаксису SQL:2003 для сохраненных подпрограмм, который также используется в IBM DB2.

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

    Рекурсивные сохраненные процедуры заблокированы по умолчанию, но могут допускаться на сервере, устанавливая переменную max_sp_recursion_depth в значение, отличное от нуля. Сохраненные функции не могут быть рекурсивными.

    5.1. Сохраненные подпрограммы и таблицы предоставления привилегий

    Сохраненные подпрограммы требуют таблицы proc в базе данных mysql. Эта таблица создана в течение процедуры установки MySQL 5.0. Если Вы наращиваете вычислительные возможности до MySQL 5.0 из более ранней версии, убедитесь, что модифицировали Ваши таблицы предоставления привилегий, чтобы удостовериться, что таблица proc существует.

    Сервер управляет таблицей mysql.proc в ответ на инструкции, которые создают, изменяют или удаляют сохраненные подпрограммы. Это значит, что сервер не обратит внимания на ручное манипулирование этой таблицей.

    Начиная с MySQL 5.0.3, система предоставления берет сохраненные подпрограммы во внимание следующим образом:

    • Привилегия CREATE ROUTINE необходима, чтобы создать сохраненные подпрограммы.

    • Привилегия ALTER ROUTINE необходима, чтобы изменять или удалять сохраненные подпрограммы. Эта привилегия предоставляется автоматически создателю подпрограммы.

    • Привилегия EXECUTE необходима, чтобы выполнить сохраненные подпрограммы. Эта привилегия предоставляется автоматически создателю подпрограммы. Также, по умолчанию характеристика SQL SECURITY для подпрограммы выставлена в DEFINER, что разрешает пользователям, которые имеют доступ к базе данных, с которой подпрограмма связана, выполнить эту подпрограмму.

    5.2. Синтаксис хранимых процедур

    Сохраненная подпрограмма является процедурой или функцией. Сохраненные подпрограммы созданы командами CREATE PROCEDURE и CREATE FUNCTION. Процедура вызывается, используя инструкцию CALL, и может только передавать обратные значения, используя переменные вывода. Функция может быть названа точно так же, как и любая другая функция языка (то есть, вызывая имя функции), и может возвращать скалярное значение. Сохраненные подпрограммы, разумеется, могут вызывать другие сохраненные подпрограммы.

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

    • Когда подпрограмма вызывается, выполняется неявный вызов USE db_name (и отменяется, когда подпрограмма завершается). Инструкции USE внутри сохраненных подпрограмм отвергнуты.

    • Вы можете квалифицировать стандартные имена с именем базы данных. Это может использоваться, чтобы обратиться к подпрограмме, которая не в текущей (актуальной) базе данных. Например, чтобы вызвать сохраненную процедуру p или функцию f, которые связаны с базой данных test, Вы можете скомандовать CALL test.p() или test.f().

    • Когда база данных удалена, все сохраненные подпрограммы, связанные с ней, также удалены.

    В MySQL 5.0.0 сохраненные подпрограммы глобальны и не связаны с базой данных. Они наследуют заданную по умолчанию базу данных с вызывающего оператора. Если внутри подпрограммы выполнено USE db_name , первоначальная заданная по умолчанию база данных восстановлена после стандартного выхода.

    MySQL поддерживает самое полезное расширение, которое позволяет использование регулярных инструкций SELECT (то есть, без того, чтобы использовать курсоры или локальные переменные) внутри сохраненной процедуры. Набор результатов такого запроса просто послан непосредственно пользователю. Многократные инструкции SELECT генерируют много наборов результатов, так что пользователь должен применять библиотеку клиентов MySQL, что поддерживает много наборов результатов. Это означает, что библиотека должна быть от MySQL не ниже 4.1. Пользователь должен также определить опцию CLIENT_MULTI_STATEMENTS, когда соединяется. Для программ на C, это может быть выполнено функцией mysql_real_connect() из C API.

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

    5.2.1. Синтаксис CREATE PROCEDURE и CREATE FUNCTION

    CREATE
       [DEFINER = { user | CURRENT_USER }]
       PROCEDURE sp_name ([proc_parameter[,...]])
       [characteristic ...] routine_body
    
    CREATE
       [DEFINER = { user | CURRENT_USER }]
       FUNCTION sp_name ([func_parameter[,...]])
       RETURNS type
       [characteristic ...] routine_body
    
    proc_parameter:
       [IN | OUT | INOUT] param_name type
    
    func_parameter:
    param_name type
    
    type:
    Любой допустимый тип данных MySQL
    
    characteristic:
    LANGUAGE SQL | [NOT] DETERMINISTIC
       | {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA}
       | SQL SECURITY {DEFINER | INVOKER}
       | COMMENT 'string'
    
    routine_body:
    Допустимая инструкция процедуры SQL
    

    Эти инструкции создают сохраненные подпрограммы. С MySQL 5.0.3, чтобы использовать их, необходимо иметь привилегию CREATE ROUTINE. Если двоичная регистрация допускается, эти инструкции могут также требовать привилегии SUPER. MySQL автоматически предоставляет создателю привилегии ALTER ROUTINE и EXECUTE.

    По умолчанию, подпрограмма связана с заданной по умолчанию базой данных. Чтобы сопоставить подпрограмму явно с другой базой данных, определите имя как db_name.sp_name, когда Вы создаете ее.

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

    SQL-режим IGNORE_SPACE применяется к встроенным функциям, но не к сохраненным подпрограммам. Всегда допустимо иметь пробелы после стандартного имени, независимо от того, допускается ли IGNORE_SPACE.

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

    Каждый параметр может быть объявлен, чтобы использовать любой тип достоверных данных, за исключением того, что не может использоваться атрибут COLLATE.

    Каждый параметр представляет собой по умолчанию параметр IN. Чтобы определять иное для параметра, используйте ключевое слово OUT или INOUT перед именем параметра.

    Обратите внимание: определение параметра как IN, OUT или INOUT допустимо только для PROCEDURE! Параметры FUNCTION всегда расцениваются как параметры IN.

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

    Для каждого параметра OUT или INOUT передайте определяемую пользователем переменную так, чтобы Вы могли получать значение, когда процедура завершается. Если Вы вызываете процедуру изнутри другой сохраненной процедуры или функции, Вы можете также передавать стандартный параметр или локальную стандартную переменную как параметр IN или INOUT.

    Предложение RETURNS может быть определено только для FUNCTION, для которой это является обязательным. Это указывает тип возврата функции, и функциональное тело должно содержать инструкцию RETURN value.

    routine_body состоит из допустимой инструкции процедуры SQL. Это может быть простая инструкция типа SELECT или INSERT , либо это может быть составная инструкция, использующая BEGIN и END. Синтаксис составного оператора описан в разделе "5.2.5. Синтаксис составного оператора BEGIN ... END". Составные инструкции могут содержать объявления, циклы и другие инструкции управляющей структуры. Синтаксис для этих инструкций описан позже в этой главе. Некоторые инструкции не позволяются в сохраненных подпрограммах.

    Инструкция CREATE FUNCTION использовалась в более ранних версиях MySQL, чтобы поддерживать UDFs (user-defined functions). UDF продолжает обеспечиваться, даже с существованием сохраненных функций. UDF может быть расценен как внешняя сохраненная функция. Однако, обратите внимание, что сохраненные функции совместно используют их пространство имен с UDF.

    Процедура или функция рассматривается как детерминированная (deterministic), если она всегда производит тот же самый результат для тех же самых входных параметров, или недетерминированная (not deterministic) в противном случае. Если при определении функции не задано DETERMINISTIC или NOT DETERMINISTIC, берется значение по умолчанию NOT DETERMINISTIC .

    Подпрограмма, которая содержит функцию NOW() (или ее синонимы) или RAND() не детерминирована, но она все еще может быть безопасна для репликации. Для NOW() двоичный файл регистрации включает timestamp и все копирует правильно. RAND() также копирует правильно, пока это вызывается только один раз внутри подпрограммы. Вы можете рассматривать стандартное выполнение timestamp и начальное значение случайного числа как неявные вводы, которые являются идентичными на главном и подчиненном узлах для репликации.

    В настоящее время характеристика DETERMINISTIC принята, но еще не используется оптимизатором. Однако, если двоичная регистрация допускается, эта характеристика воздействует на то, которые стандартные определения MySQL принимает.

    Несколько характеристик обеспечивают информацию относительно характера использования данных подпрограммой. CONTAINS SQL указывает, что подпрограмма не содержит инструкции, которые читают или записывают данные. NO SQL указывает, что подпрограмма не содержит никаких инструкций SQL. READS SQL DATA указывает, что подпрограмма содержит инструкции, которые читают данные, но не инструкции, чтобы те данные записывать. MODIFIES SQL DATA указывает, что подпрограмма содержит инструкции, которые могут записывать данные. CONTAINS SQL значение по умолчанию, если ни одна из этих характеристик не дана явно. Эти характеристики только консультативные. Сервер не использует их, чтобы ограничить то, какие виды инструкций подпрограмме позволено выполнить.

    Характеристика SQL SECURITY может использоваться, чтобы определить, должна ли подпрограмма быть выполнена, используя разрешения пользователя, который создает подпрограмму, или пользователя, который ее вызывает. Значение по умолчанию: DEFINER. Это свойство ново в SQL:2003. Создатель или исполнитель должен иметь разрешение обратиться к базе данных, с которой подпрограмма связана. Начиная с MySQL 5.0.3, необходимо иметь привилегию EXECUTE, чтобы выполнить подпрограмму. Пользователь, который должен иметь эту привилегию, является создателем или исполнителем в зависимости от того, как установлена характеристика SQL SECURITY.

    Факультативное предложение DEFINER определяет логин MySQL, который нужно использовать при проверке привилегий доступа в стандартном времени выполнения для подпрограмм, которые имеют характеристику SQL SECURITY DEFINER. Предложение DEFINER было добавлено в MySQL 5.0.20.

    Если дано значение user, это должно быть логином MySQL в формате 'user_name'@'host_name' (тот же самый формат используется в инструкции GRANT). Параметры user_name и host_name обязательны. CURRENT_USER также может быть дан как CURRENT_USER(). Заданное по умолчанию для DEFINER: пользователь, который выполняет CREATE PROCEDURE, CREATE FUNCTION или инструкцию (аналогично DEFINER=CURRENT_USER).

    Если Вы определяете предложение DEFINER, Вы не можете устанавливать значение к любому логину (только к Вашему собственному), если Вы не имеете привилегию SUPER. Эти правила определяют допустимые значения пользователя DEFINER:

    • Если Вы не имеете привилегию SUPER, единственное допустимое значение user: Ваш собственный логин, определенный буквально или используя CURRENT_USER. Вы не можете устанавливать DEFINER к некоторому другому логину.

    • Если Вы имеете привилегию SUPER, Вы можете определять любой синтаксически допустимый логин. Если он фактически не существует, будет сгенерировано предупреждение.

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

    MySQL сохраняет установку переменной системы sql_mode, которая была во время создания подпрограммы, и всегда выполняет подпрограмму именно с этой установкой.

    Когда подпрограмма вызывается, выполняется неявное USE db_name (и отменяется по завершении). Инструкции USE внутри сохраненных подпрограмм отвергнуты.

    Начиная с MySQL 5.0.18, сервер использует тип данных стандартного параметра или функционального возвращаемого значения следующим образом. Эти правила также относятся к локальным стандартным переменным, созданным инструкцией DECLARE.

    • Назначения проверены на предмет несоответствия типов данных и переполнение. Преобразование и проблемы переполнения приводит к предупреждениям или ошибкам в строгом режиме.

    • Для символьных типов данных, если имеется предложение CHARACTER SET в объявлении, используются определенный набор символов и заданное по умолчанию объединение. Если не имеется никакого такого предложения, используются наборы символов базы данных и объединение, которые были актуальными во время написания подпрограммы (они заданы значениями переменных системы character_set_database и collation_database). Атрибут COLLATE не обеспечивается. Это включает использование BINARY, потому что в этом контексте BINARY определяет двоичное объединение набора символов.

    • Только скалярные значения могут быть назначены к параметрам или переменным. Например, инструкция типа SET x=(SELECT 1,2) глубоко ошибочна.

    До MySQL 5.0.18 параметры, возвращаемые значения и локальные переменные обрабатываются как элементы в выражениях, и подчиненны автоматическому (тихому) преобразованию и усечению. Сохраненные функции игнорируют установку sql_mode.

    Предложение COMMENT представляет собой очередное расширение MySQL и может использоваться, чтобы описать сохраненную подпрограмму. Эта информация отображается командами SHOW CREATE PROCEDURE и SHOW CREATE FUNCTION.

    MySQL позволяет подпрограммам содержать инструкции DDL, например, CREATE и DROP. MySQL также позволяет сохраненным процедурам (но не сохраненным функциям) содержать SQL-инструкции транзакций, типа COMMIT. Сохраненные функции не могут содержать инструкции, которые делают явное или неявное завершение транзакции или обратную перемотку. Поддержка для этих инструкций не требуется стандартом SQL, который четко заявляет, что каждый поставщик СУБД может решать, позволять ли это.

    Сохраненные подпрограммы не могут использовать LOAD DATA INFILE.

    Инструкции, которые возвращают набор результатов, не могут использоваться внутри сохраненной функции. Это включает инструкции SELECT, которые не используют INTO, чтобы выбрать значения столбца в переменные, инструкции SHOW и другие инструкции, типа EXPLAIN. Для инструкций, которые могут быть заданы при функциональном определении, но возвращают набо результатов, произойдет ошибочка Not allowed to return a result set from a function (ER_SP_NO_RETSET_IN_FUNC). Для инструкций, которые могут быть определены только во время выполнения, происходит ошибка PROCEDURE %s can't return a result set in the given context (ER_SP_BADSELECT).

    Обратите внимание: до MySQL 5.0.10 сохраненные функции, созданные с CREATE FUNCTION, не должны содержать ссылки к таблицам, с ограниченными исключительными ситуациями. Они могут включать некоторые инструкции SET, которые содержат ссылки на таблицы, например, SET a:= (SELECT MAX(id) FROM t), и инструкции SELECT, которые выбирают значения непосредственно в переменные, например, SELECT i INTO var1 FROM t.

    Следующее показывает пример простой сохраненной процедуры, которая использует параметр OUT. Пример использует команду delimiter клиента mysql, чтобы изменить операторный разделитель с ; на // в то время как процедура определяется. Это позволяет использовать разделитель ; в теле процедуры, которое будет передано на сервер.

    mysql> delimiter //
    mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
        -> BEGIN
        ->   SELECT COUNT(*) INTO param1 FROM t;
        -> END;
        -> //
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> delimiter ;
    mysql> CALL simpleproc(@a);
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT @a;
    +------+
    | @a   |
    +------+
    | 3    |
    +------+
    1 row in set (0.00 sec)
    

    При использовании команды delimiter, Вы должны избежать использования наклонной черты влево (\), потому что это escape-символ для MySQL.

    Следующее представляет собой пример функции, которая берет параметр, выполняет операцию, использующую функцию SQL, и возвращает результат. В этом случае, ненужно использовать разделитель, потому что функциональное определение не содержит никакой внутренней ;, значит точку с запятой можно использовать как операторный разделитель:

    mysql> CREATE FUNCTION hello (s CHAR(20)) RETURNS CHAR(50)
        -> RETURN CONCAT('Hello, ',s,'!');
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT hello('world');
    +----------------+
    | hello('world') |
    +----------------+
    | Hello, world!  |
    +----------------+
    1 row in set (0.00 sec)
    

    Сохраненная функция возвращает значение типа данных, определенного в предложении RETURNS. Если инструкция RETURN возвращает значение иного типа, значение приведено к соответствующему типу. Например, если функция возвращает значение ENUM или SET, но инструкция RETURN возвращает целое число, значение, возвращенное из функции: строка для соответствующего ENUM-члена набора элементов SET.

    5.2.2. Синтаксис ALTER PROCEDURE и ALTER FUNCTION

    ALTER {PROCEDURE | FUNCTION} sp_name
          [characteristic ...]
    
    characteristic:
    {CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
       | SQL SECURITY { DEFINER | INVOKER }
       | COMMENT 'string'
    

    Эта инструкция может использоваться, чтобы изменить характеристики сохраненной процедуры или функции. Начиная с MySQL 5.0.3, Вы должны иметь привилегию ALTER ROUTINE для подпрограммы. Эта привилегия предоставляется автоматически стандартному создателю. Если двоичная регистрация допускается, эта инструкция могла бы также требовать привилегии SUPER. Больше чем одно изменение может быть определено в команде ALTER PROCEDURE или ALTER FUNCTION.

    5.2.3. Синтаксис DROP PROCEDURE и DROP FUNCTION

    DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
    

    Эта инструкция используется, чтобы удалить сохраненную процедуру или функцию. То есть определенная подпрограмма будет удалена с сервера. Начиная с MySQL 5.0.3, Вы должны иметь привилегию ALTER ROUTINE для подпрограммы. Такая привилегия предоставляется автоматически создателю.

    Предложение IF EXISTS является расширением MySQL. Это предотвращает ошибку, если процедура или функция не существует. Будет произведено предупреждение, которое может просматриваться с помощью команды SHOW WARNINGS.

    5.2.4. Синтаксис команды CALL

    CALL sp_name([parameter[,...]])
    

    Инструкция CALL вызывает процедуру, которая была определена предварительно, с помощью команды CREATE PROCEDURE.

    CALL может передавать обратно значения к параметрам использования вызывающего оператора, которые объявлены как OUT или INOUT. Это также вернет число строк, на которые воздействовал запрос, это же значение программа пользователя может получать в уровне SQL, вызывая функцию ROW_COUNT() или из C API функцией mysql_affected_rows().

    Чтобы вернуть значение из процедуры, использующей параметр OUT или INOUT, передайте параметр посредством переменной пользователя, и затем проверьте значение переменной после возврата из процедуры. Если Вы вызываете процедуру изнутри другой сохраненной процедуры или функции, Вы можете также передавать стандартный параметр или локальную стандартную переменную как параметр IN или INOUT. Для параметра INOUT инициализируйте значение перед его передачей процедуре. Следующая процедура имеет параметр OUT, который процедура устанавливает в текущую (актуальную) версию сервера, и значение INOUT, которое процедура увеличивает:

    CREATE PROCEDURE p (OUT ver_param VARCHAR(25), INOUT incr_param INT)
    BEGIN
      # Set value of OUT parameter
      SELECT VERSION() INTO ver_param;
      # Increment value of INOUT parameter
      SET incr_param = incr_param + 1;
    END;
    

    Перед вызовом процедуры, инициализируйте переменную, которая будет передана как параметр INOUT. После вызова процедуры, значения в двух переменных будут установлены или изменены:

    mysql> SET @increment = 10;
    mysql> CALL p(@version, @increment);
    mysql> SELECT @version, @increment;
    +------------+------------+
    | @version   | @increment |
    +------------+------------+
    | 5.0.25-log | 11         |
    +------------+------------+
    

    Если Вы пишете программы на C, которые выполняют сохраненные процедуры с инструкцией SQL CALL, Вы должны установить флажок CLIENT_MULTI_RESULTS, когда Вы вызываете mysql_real_connect(), либо установить CLIENT_MULTI_STATEMENTS. Это потому, что каждый CALL возвращает результат, чтобы указать состояние обращения, в дополнение к любым наборам результатов, которые могли бы быть возвращены инструкциями, выполненными внутри процедуры. Чтобы обрабатывать результат инструкции CALL, используйте цикл, который вызывает mysql_next_result() чтобы определить, имеется ли большее количество результатов.

    5.2.5. Синтаксис составного оператора BEGIN ... END

       [begin_label:] BEGIN
       [statement_list]
    END [end_label]
    

    Синтаксис BEGIN ... END используется для записи составных инструкций, которые могут появляться внутри сохраненных подпрограмм и триггеров. Составная инструкция может содержать много инструкций, взятых в ключевые слова BEGIN и END. Здесь statement_list представляет список инструкций. Каждая инструкция внутри statement_list должна быть завершена операторным разделителем точкой с запятой (;). Обратите внимание, что список statement_list факультативный, что означает, что пустая составная инструкция (BEGIN END) допустима.

    Использование многих инструкций требует, чтобы пользователь был способен послать операторные строки, содержащие операторный разделитель ;. Это обработано в клиенте командной строки mysql командой delimiter. Изменение разделителя конца инструкции ; (например, на //) позволяет ; использоваться в стандартном теле.

    Составная инструкция может быть помечена. end_label не может быть дан, если begin_label также не присутствует. Если оба присутствуют, они должны быть те же самые.

    Факультативное предложение [NOT] ATOMIC еще не обеспечивается. Это означает, что никакие точки сохранения транзакций не установлены в начале блока команды, и предложение BEGIN, используемое в этом контексте не имеет никакого эффекта на текущей (актуальной) транзакции.

    5.2.6. Синтаксис DECLARE

    Инструкция DECLARE используется, чтобы определить различные элементы, локальные для подпрограммы:

    Инструкции SIGNAL и RESIGNAL в настоящее время не обеспечиваются.

    DECLARE позволяется только внутри BEGIN ... END и должен быть в начале, перед любыми другими инструкциями.

    Объявления должны следовать за некоторым порядком. Курсоры должны быть объявлены перед объявлением драйверов и переменных, условия должны быть объявлены перед объявлениями, курсорами или драйверами.

    5.2.7. Переменные в сохраненных подпрограммах

    Вы можете объявлять и использовать переменные внутри подпрограммы.

    5.2.7.1. Локальные переменные DECLARE

    DECLARE var_name[,...] type
            [DEFAULT value]
    

    Эта инструкция используется, чтобы объявить локальные переменные. Чтобы обеспечивать значение по умолчанию для переменной, включите предложение DEFAULT. Значение может быть определено как выражение, оно не обязательно должно быть константой. Если предложение DEFAULT отсутствует, начальное значение NULL.

    Локальные переменные обрабатываются подобно стандартным параметрам относительно типа данных и проверки переполнения.

    Область (контекст) локальной переменной: внутри блока BEGIN ... END, где это объявлено. Переменная может упоминаться в блоках, вложенных внутри блока объявления, за исключением тех блоков, которые объявляют переменную с тем же самым именем.

    5.2.7.2. Команда SET

    SET var_name = expr
        [, var_name = expr] ...
    

    Инструкция SET в сохраненных подпрограммах представляет собой расширенную версию общей инструкции SET. Вызванные переменные могут быть объявлены внутри подпрограммы или глобальными переменными системы.

    Инструкция SET в сохраненных подпрограммах выполнена как часть синтаксиса SET. Это позволяет расширенный синтаксис SET a=x, b=y, ..., где различные виды переменных (локально объявленные, глобальные и переменные сеанса сервера могут быть смешаны. Это также позволяет комбинации локальных переменных и некоторых параметров, которые имеют смысл только для переменных системы. В этом случае, параметры распознаны, но игнорируются.

    5.2.7.3. Команда SELECT ... INTO

    SELECT col_name[,...]
           INTO var_name[,...] table_expr
    

    Этот синтаксис SELECT сохраняет выбранные столбцы непосредственно в переменные. Следовательно, только одиночная строка может быть получена.

    SELECT id,data INTO x,y FROM test.t1 LIMIT 1;
    

    Имена переменных пользователя не чувствительны к регистру. Важно: имена переменных SQL не должны совпадать с именами столбцов. Если инструкция SQL, типа SELECT ... INTO, содержит ссылку к столбцу, и есть объявленная локальная переменная с тем же самым именем, MySQL в настоящее время интерпретирует ссылку как имя переменной. Например, в следующей инструкции xname интерпретируется как ссылка к переменной, а не к столбцу с именем xname:

    CREATE PROCEDURE sp1 (x VARCHAR(5))
    BEGIN
      DECLARE xname VARCHAR(5) DEFAULT 'bob';
      DECLARE newname VARCHAR(5);
      DECLARE xid INT;
      SELECT xname, id INTO newname, xid FROM table1 WHERE xname = xname;
      SELECT newname;
    END;
    

    Когда эта процедура вызвана, переменная newname возвращает значение 'bob' независимо от значения столбца table1.xname.

    5.2.8. Условия и драйверы

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

    5.2.8.1. DECLARE условий

    DECLARE condition_name CONDITION FOR
            condition_value
    
    condition_value:
    SQLSTATE [VALUE] sqlstate_value
       | mysql_error_code
    

    Эта инструкция определяет условия, которые нуждаются в специфической обработке. Это сопоставляет имя с определенным условием ошибки. Имя может впоследствии использоваться в инструкции DECLARE HANDLER.

    Здесь condition_value может быть значением SQLSTATE или же кодом ошибки MySQL.

    5.2.8.2. DECLARE драйвера

    DECLARE handler_type HANDLER FOR
            condition_value[,...] statement
    
    handler_type:
       CONTINUE | EXIT | UNDO
    
    condition_value:
    SQLSTATE [VALUE] sqlstate_value
       | condition_name | SQLWARNING | NOT FOUND | SQLEXCEPTION
       | mysql_error_code
    

    Инструкция DECLARE ... HANDLER определяет драйверы, с каждым из которых может иметь дело одно или большее количество условий. Если одно из этих условий происходит, определенная инструкция statement будет выполнена. Инструкция может быть простой инструкцией (например, SET var_name = value), или это может быть составной инструкцией, записанной с помощью парочки BEGIN и END.

    Для драйвера CONTINUE выполнение текущей подпрограммы продолжается после выполнения инструкции драйвера. Для драйвера EXIT выполнение завершается для составной инструкции BEGIN ... END, в которой драйвер объявлен. Это истинно, даже если условие происходит во внутреннем блоке. Инструкция типа драйвера UNDO еще не обеспечивается (пока?).

    Если происходит условие, для которого никакой драйвер не был объявлен, заданное по умолчанию действие: EXIT.

    Параметр condition_value может быть любым из следующих значений:

    • Значение SQLSTATE или MySQL-код ошибки.

    • Имя условия, предварительно определенное с DECLARE ... CONDITION.

    • SQLWARNING (краткая запись для всех кодов SQLSTATE, которые начинаются с 01).

    • NOT FOUND (краткая запись для всех кодов SQLSTATE, которые начинаются с 02).

    • SQLEXCEPTION (краткая запись для всех кодов SQLSTATE, не охваченных SQLWARNING или NOT FOUND).

    Пример:

    mysql> CREATE TABLE test.t (s1 int,primary key (s1));
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> delimiter //
    mysql> CREATE PROCEDURE handlerdemo ()
        -> BEGIN
        ->   DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
        ->   SET @x = 1;
        ->   INSERT INTO test.t VALUES (1);
        ->   SET @x = 2;
        ->   INSERT INTO test.t VALUES (1);
        ->   SET @x = 3;
        -> END;
        -> //
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> CALL handlerdemo()//
    Query OK, 0 rows affected (0.00 sec)
    mysql> SELECT @x//
    +------+
    | @x   |
    +------+
    | 3    |
    +------+
    1 row in set (0.00 sec)
    

    Пример сопоставляет драйвер с SQLSTATE 23000, который происходит для ошибки дублирования ключа. Обратите внимание, что @x равен 3, это показывает что MySQL перейдет к концу процедуры. Если строка DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1; не была представлена, MySQL примет заданный по умолчанию путь (EXIT) после второй неудачи INSERT из-за ограничения PRIMARY KEY, а SELECT @x возвратит 2.

    Если Вы хотите игнорировать условие, Вы можете объявлять драйвер CONTINUE для этого и сопоставлять его с пустым блоком. Например:

    DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;
    

    5.2.9. Курсоры

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

    Курсоры должны быть объявлены перед объявлением драйверов и переменных, а условия должны быть объявлены перед объявлением курсоров и драйверов.

    Пример:

    CREATE PROCEDURE curdemo()
    BEGIN
      DECLARE done INT DEFAULT 0;
      DECLARE a CHAR(16);
      DECLARE b,c INT;
      DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
      DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
      DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
      OPEN cur1;
      OPEN cur2;
      REPEAT
        FETCH cur1 INTO a, b;
        FETCH cur2 INTO c;
        IF NOT done THEN
           IF b < c THEN INSERT INTO test.t3 VALUES (a,b);
              ELSE INSERT INTO test.t3 VALUES (a,c);
           END IF;
        END IF;
      UNTIL done END REPEAT;
      CLOSE cur1;
      CLOSE cur2;
    END
    

    5.2.9.1. Объявление курсоров

    DECLARE cursor_name
            CURSOR FOR select_statement
    

    Эта инструкция объявляет курсор. Много курсоров может быть объявлено в подпрограмме, но каждый курсор в данном блоке должен иметь уникальное имя.

    Инструкция SELECT не может иметь предложение INTO.

    5.2.9.2. Инструкция OPEN

    OPEN cursor_name
    

    Эта инструкция открывает предварительно объявленный курсор.

    5.2.9.3. Инструкция FETCH

    FETCH cursor_name
    INTO var_name [, var_name] ...
    

    Эта инструкция выбирает следующую строку (если строка существует), используя определенный открытый курсор, и продвигает указатель курсора.

    Если больше нет доступных строк, происходит условие No Data со значением SQLSTATE 02000. Чтобы обнаружить это условие, Вы можете установить драйвер для этого. Пример показывается в разделе "5.2.9. Курсоры".

    5.2.9.4. Инструкция CLOSE

    CLOSE cursor_name
    

    Эта инструкция закрывает предварительно открытый курсор. Если курсор не закрыт явно, он все равно закроется в конце составной инструкции, в которой он был объявлен.

    5.2.10. Конструкции управления потоком данных

    Конструкции IF, CASE, LOOP, WHILE, REPLACE ITERATE и LEAVE полностью выполнены.

    Многие из этих конструкций содержат другие инструкции, как обозначено спецификациями грамматики в следующих разделах. Такие конструкции могут быть вложены. Например, IF мог бы содержать цикл времени, который непосредственно содержит WHILE, который в свою очередь включает в себя оператор CASE. Циклы FOR в настоящее время не обеспечиваются.

    5.2.10.1. Инструкция IF

    IF search_condition THEN statement_list
       [ELSEIF search_condition
       THEN statement_list] ...
       [ELSE statement_list]
    END IF
    

    IF реализован как базисная условная конструкция. Если выражение search_condition истинно, соответствующий список инструкции SQL выполнен. Если пары search_condition не нашлось, будет выполнен операторный список в предложении ELSE. Каждый statement_list состоит из одной или большего количества инструкций.

    Обратите внимание: имеется также функция IF(), которая отличается от команды IF, описанной здесь.

    5.2.10.2. Инструкция CASE

       CASE case_value WHEN when_value
            THEN statement_list
            [WHEN when_value THEN statement_list] ...
            [ELSE statement_list]
       END CASE
    

    Или:

       CASE WHEN search_condition THEN statement_list
            [WHEN search_condition THEN statement_list] ...
            [ELSE statement_list]
       END CASE
    

    Инструкция CASE для сохраненных подпрограмм осуществляет сложную условную конструкцию. Если search_condition равно true, соответствующий список инструкций SQL выполнен. Если никакие условия не подошли, отрабатывается операторный список в предложении ELSE. Каждый statement_list состоит из одной или большего количества инструкций.

    Обратите внимание: синтаксис инструкции CASE, показанной здесь для использования внутри сохраненных подпрограмм немного отличается от такового выражения в SQL. Инструкция CASE не может иметь предложение ELSE NULL, и она завершена END CASE вместо END.

    5.2.10.3. Инструкция LOOP

       [begin_label:] LOOP
        statement_list
       END LOOP [end_label]
    

    LOOP осуществляет простую конструкцию цикла, допуская повторенное выполнение операторного списка, который состоит из одной или большего количества инструкций. Инструкции внутри цикла повторены, пока цикл не покидается. Обычно это выполнено инструкцией LEAVE.

    Инструкция LOOP может быть помечена. end_label не может быть дан, если нет begin_label. Если оба присутствуют, они должны быть те же самые.

    5.2.10.4. Инструкция LEAVE

    LEAVE label
    

    Эта инструкция используется, чтобы из выйти любой помеченной конструкции управления потоком данных. Это может использоваться внутри BEGIN ... END или же конструкций цикла (LOOP, REPEAT, WHILE).

    5.2.10.5. Инструкция ITERATE

    ITERATE label
    

    ITERATE может появляться только внутри инструкций LOOP, REPEAT и WHILE. ITERATE означает "выполнить цикл снова ".

    Пример:

    CREATE PROCEDURE doiterate(p1 INT)
    BEGIN
      label1: LOOP
        SET p1 = p1 + 1;
        IF p1 < 10 THEN ITERATE label1;
        END IF;
        LEAVE label1;
      END LOOP label1;
      SET @x = p1;
    END
    

    5.2.10.6. Инструкция REPEAT

    [begin_label:]
      REPEAT statement_list
        UNTIL search_condition
      END REPEAT
    [end_label]
    

    Операторный список внутри инструкции REPEAT повторен, пока search_condition равно true. Таким образом, REPEAT всегда проходит цикл по крайней мере один раз. Перечень statement_list состоит из одной или большего числа инструкций. Инструкция REPEAT может быть помечена по обычным правилам.

    mysql> delimiter //
    mysql> CREATE PROCEDURE dorepeat(p1 INT)
        -> BEGIN
        ->   SET @x = 0;
        ->   REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
        -> END
        -> //
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> CALL dorepeat(1000)//
    Query OK, 0 rows affected (0.00 sec)
    mysql> SELECT @x//
    +------+
    | @x   |
    +------+
    | 1001 |
    +------+
    1 row in set (0.00 sec)
    

    5.2.10.7. Инструкция WHILE

    [begin_label:]
      WHILE search_condition DO statement_list
      END WHILE
    [end_label]
    

    Операторный список внутри инструкции WHILE повторен, пока search_condition равно true. Инструкция WHILE может быть помечена. Пример:

    CREATE PROCEDURE dowhile()
    BEGIN
      DECLARE v1 INT DEFAULT 5;
      WHILE v1 > 0 DO
        ...
        SET v1 = v1 - 1;
      END WHILE;
    END
    

    5.3. Сохраненные процедуры, функции, триггеры и LAST_INSERT_ID()

    Внутри тела сохраненной подпрограммы (процедуры или функции) или триггера значение LAST_INSERT_ID() меняется по обычным правилам. Эффект сохраненной подпрограммы или триггера на значение LAST_INSERT_ID(), который замечен следующими инструкциями, зависит от вида подпрограммы:

    • Если сохраненная процедура выполняет инструкции, которые изменяют значение LAST_INSERT_ID(), измененное значение будет замечено инструкциями, которые следуют за вызовом процедуры.

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

    5.4. Сохраненные процедуры, функции, триггеры и репликация

    • В MySQL 5.0 сохраненные процедуры и функции работают с репликацией?

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

    • Будут ли сохраненные процедуры и функции, созданные на главном сервере, скопированы на подчиненный?

      Да, создание сохраненных процедур и функций, выполненное через нормальные инструкции DDL, скопируется на подчиненный, так что объекты будут существовать на обеих серверах. Инструкции ALTER и DROP для сохраненных процедур и функций также скопируются.

    • Как реплицируются действия, которые происходят внутри сохраненных процедур и скопированных функций?

      MySQL записывает каждое событие DML, которое происходит в сохраненной процедуре, и копирует эти индивидуальные действия на подчиненный сервер. Фактические обращения, сделанные, чтобы выполнить сохраненные процедуры не скопируются. Сохраненные функции, которые изменяют данные, регистрируются как функциональные вызовы, а не как события DML, которые происходят внутри каждой функции.

    • Есть ли специальные требования защиты для использования сохраненных процедур и функций вместе с репликацией?

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

      • Любому пользователю, желающему создать сохраненные функции, нужно предоставлять SUPER привилегию.

      • В качестве альтернативы, DBA может устанавливать переменную системы log_bin_trust_function_creators в 1, что позволяет любому со стандартной привилегией CREATE ROUTINE создавать сохраненные функции.

      Обратите внимание: до MySQL 5.0.16 эти ограничения также относятся к сохраненным процедурам, и переменная системы именована log_bin_trust_routine_creators.

    • Какие ограничения существуют для копирования сохраненной процедуры и функциональных действий?

      Не детерминированные (произвольные) или основанные на времени действия, внедренные в сохраненных процедурах, не могут копироваться правильно. Для них очень характерны беспорядочно произведенные не предсказуемые результаты, которые не могут быть точно воспроизведены, а, следовательно, произвольные действия, скопированные на подчиненный сервер, не будут отражать, что именно выполнили на главном сервере. Обратите внимание, что объявление сохраненных функций как DETERMINISTIC или установка переменной системы log_bin_trust_function_creators в 0 не будет позволять вызывать произвольно оцененные операции.

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

      В заключение, нетранзакционные таблицы, для которых происходят ошибки в течение больших действий DML (типа объемных вставок), могут испытывать проблемы дублирования, в которых главный сервер может частично модифицироваться из действия DML, но никакие модификации не выполнены на подчиненном из-за ошибок, которые произошли. Обойти проблему можно с ключевым словом IGNORE так, чтобы модификации на главном сервере, которые вызывают ошибки, игнорировались, а модификации, которые не вызывают ошибок, скопируются на подчиненный.

    • Предшествующие ограничения воздействуют на способность MySQL делать восстановление до контрольной точки?

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

    • Что будет делать MySQL, чтобы исправить вышеупомянутые ограничения?

      Будущий выпуск MySQL, как ожидается, даст выбор в том, как репликация должна быть обработана:

      • Операторно-основанная репликация (текущая реализация).

      • Дублирование уровня строки (которое решит все ограничения, описанные ранее).

    • Триггеры работают с репликацией?

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

    • Как действия, выполненные через триггер на главном сервере, скопированы на подчиненный?

      Сначала, триггеры, которые существуют на главном сервере, должны быть вновь созданы на подчиненном сервере. Если это выполнено, поток дублирования работает как любая другая стандартная инструкция DML, которая участвует в дублировании. Например, рассмотрите таблицу EMP, которая имеет триггер AFTER insert, существующий на главном сервере. Та же самая таблица и триггер существуют также и на подчиненном сервере. Поток дублирования был бы:

      1. Инструкция INSERT сделана в EMP.

      2. Триггер AFTER сработал на EMP.

      3. Инструкция INSERT записана в двоичный файл регистрации.

      4. Подчиненный сервер подбирает инструкцию INSERT к EMP и выполняет ее.

      5. Триггер AFTER в EMP, который существует на подчиненном сервере, активизируется.

    5.5. Двоичная регистрация сохраненных подпрограмм и триггеров

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

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

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

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

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

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

    Разработка регистрации сохраненной подпрограммы в MySQL 5.0 может быть получена в итоге следующим образом:

    • До MySQL 5.0.6: в начальной реализации регистрации сохраненной подпрограммы, инструкции, которые создают сохраненные подпрограммы, и инструкции CALL не регистрируются. Эти вычеркивания могут вызывать проблемы для восстановления данных и дублирования.

    • MySQL 5.0.6: инструкции, которые создают сохраненные подпрограммы, и инструкции CALL регистрируются. Сохраненные функциональные вызовы регистрируются, когда они происходят в инструкциях, которые модифицируют данные (потому что те инструкции регистрируются). Однако, функциональные вызовы не регистрируются, когда они происходят в инструкциях типа SELECT, которые не изменяют данные, даже если изменение данных происходит непосредственно внутри функции, это может вызвать проблемы. При некоторых обстоятельствах, функции и процедуры могут иметь различные эффекты если выполнено в разное время или на различных серверах (главном или подчиненном), и таким образом они могут быть опасны для восстановления данных или дублирования. Чтобы обрабатывать это, приняты меры, чтобы позволить идентификацию безопасных подпрограмм и предотвратить создание опасных подпрограмм (за исключением создаваемых пользователями с достаточными привилегиями).

    • MySQL 5.0.12: для сохраненных функций, когда функциональный вызов, который изменяет данные, происходит внутри не регистрируемой инструкции типа SELECT, сервер регистрирует инструкцию DO func_name(), которая вызывает функцию так, чтобы функция была выполнена в течение восстановления данных или дублирования на подчиненные серверы. Для сохраненных процедур, сервер не регистрирует инструкции CALL. Вместо этого, он регистрирует индивидуальные инструкции внутри процедуры, которые выполнены в результате CALL. Это устраняет проблемы, которые могут происходить, когда процедура выполнялась бы на подчиненном сервере иным способом, чем на главном.

    • MySQL 5.0.16: процедура, регистрирующая изменения, сделанные в 5.0.12, позволяет ослабить условия на опасных подпрограммах для сохраненных процедур. Следовательно, интерфейс пользователя для управления этими условиями пересмотрен, чтобы применить только к функциям. Создатели процедуры больше не связаны ими.

    • MySQL 5.0.17: регистрация сохраненных функций также, как и инструкции DO func_name() (для изменений, сделанных в 5.0.12), регистрируется как инструкции SELECT func_name() для лучшего контроля проверки ошибок.

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

    • Чтобы создавать или изменять сохраненную функцию, Вы должны иметь привилегию SUPER, в дополнение к привилегии CREATE ROUTINE или ALTER ROUTINE, которая обычно требуется.

    • Когда Вы создаете сохраненную функцию, Вы должны объявить, что это детерминировано или не изменяет данные. Иначе, это может быть опасно для восстановления данных или дублирования. Два набора функциональных характеристик применяются здесь:

      • Характеристики DETERMINISTIC и NOT DETERMINISTIC указывают, производит ли функция всегда тот же самый результат для входных данных. Значение по умолчанию: NOT DETERMINISTIC, если никакая характеристика не дана, так что Вы должны определить DETERMINISTIC явно, чтобы объявить, что функция детерминирована.

        Использование функции NOW() (или синонимов) либо RAND() не обязательно делает функцию не детерминированной. Для NOW() двоичный файл регистрации включает timestamp и все копирует правильно. RAND() также копируется правильно, пока это вызывается только один раз внутри функции. Вы можете рассматривать функциональное выполнение timestamp и начальное значение случайного числа как неявные вводы, которые являются идентичными на главном и подчиненном серверах.

        SYSDATE() не воздействует на timestamp в двоичном файле регистрации, так что это заставляет сохраненные подпрограммы быть не детерминированными, если используется регистрация, основанная на командах. Этого не происходит, если сервер запущен с опцией --sysdate-is-now, чтобы заставить SYSDATE() быть псевдонимом для NOW().

      • Характеристики CONTAINS SQL, NO SQL, READS SQL DATA и MODIFIES SQL DATA обеспечивают информацию относительно того, читает ли функция или записывает данные. NO SQL или READS SQL DATA указывают, что функция не изменяет данные, но Вы должны определить одну из них явно, потому что значение по умолчанию: CONTAINS SQL, если никакая характеристика не дана.

      По умолчанию для инструкции CREATE FUNCTION, которая будет принята, должны быть определены явно DETERMINISTIC или что-то из NO SQL и READS SQL DATA. Иначе происходит ошибка:

      ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL,
      or READS SQL DATA in its declaration and binary logging is enabled (you
      *might* want to use the less safe log_bin_trust_function_creators variable)
      

      Оценка характера функции основана на честности ее создателя: MySQL не проверяет, что функция, объявленная DETERMINISTIC, не содержит никаких инструкций, которые производят не детерминированные результаты.

    • Чтобы ослабить предшествующие условия на функциональном создании (что Вы должны иметь привилегию SUPER, и что функция должна быть объявлена детерминированной или не изменять данные), установите глобальную переменную системы log_bin_trust_function_creators в 1. По умолчанию, эта переменная имеет значение 0, но Вы можете изменить это:

      mysql> SET GLOBAL log_bin_trust_function_creators = 1;
      

      Вы можете также устанавливать эту переменную, используя опцию --log-bin-trust-function-creators при старте сервера.

      Если двоичная регистрация не допускается, log_bin_trust_function_creators не применяется, и для стандартного создания не требуется привилегия SUPER.

    Триггер подобен сохраненным функциям, так что предшествующие замечания относительно функций также относятся к ним со следующей исключительной ситуацией: CREATE TRIGGER не имеет факультативной характеристики DETERMINISTIC, так что триггеры приняты, чтобы быть всегда детерминированными. Однако, это предположение могло бы в некоторых случаях быть недопустимым. Например, функция UUID() не детерминирована (и не копируется!). Вы должны быть внимательны относительно использования таких функций в триггерах.

    Триггер может модифицировать таблицы (начиная с MySQL 5.0.10), так что сообщения об ошибках, подобны тем же для сохраненных функций с CREATE TRIGGER, если Вы не имеете привилегии SUPER, а log_bin_trust_function_creators равна 0.

    5.6 MySQL 5 FAQ по хранимым подпрограммам

    5.6.1: Есть ли форум для обсуждения сохраненных подпрограмм в MySQL?

    Да. http://forums.mysql.com/list.php?98.

    5.6.2: Где я могу найти спецификацию ANSI SQL 2003 для сохраненных процедур?

    К сожалению, официальные спецификации не свободно доступны (ANSI делает их доступными для приобретения). Однако, имеются книги, типа SQL-99 Complete, Really by Peter Gulutzan and Trudy Pelzer, которые дают всесторонний краткий обзор стандарта, включая покрытие сохраненных процедур.

    5.6.3: Как управлять сохраненными подпрограммами?

    Лучше использовать чистую схему наименования сохраненных подпрограмм. Вы можете управлять сохраненными подпрограммами с помощью CREATE [FUNCTION|PROCEDURE], ALTER [FUNCTION|PROCEDURE], DROP [FUNCTION|PROCEDURE] и SHOW CREATE [FUNCTION|PROCEDURE]. Вы можете получать информацию относительно существующих сохраненных процедур, используя таблицу ROUTINES в базе данных INFORMATION_SCHEMA.

    5.6.4: Есть ли способ просматривать все сохраненные процедуры и функции в базе данных?

    Да. Для базы данных dbname используйте этот запрос к таблице INFORMATION_SCHEMA.ROUTINES:

    SELECT ROUTINE_TYPE, ROUTINE_NAME
           FROM INFORMATION_SCHEMA.ROUTINES
           WHERE ROUTINE_SCHEMA='dbname';
    

    Тело сохраненной подпрограммы может просматриваться, используя SHOW CREATE FUNCTION (для сохраненной функции) или SHOW CREATE PROCEDURE (для сохраненной процедуры).

    5.6.5: Где сохраненные процедуры сохранены?

    В таблице proc базы данных mysql. Однако, Вы не должны обращаться к таблицам в базе данных системы непосредственно. Вместо этого, используйте SHOW CREATE FUNCTION, чтобы получить информацию относительно сохраненных функций и SHOW CREATE PROCEDURE, чтобы получить информацию относительно сохраненных процедур.

    Вы можете также сделать запрос к таблице ROUTINES в базе данных INFORMATION_SCHEMA для информации относительно этой таблицы.

    5.6.6: Возможно ли группировать сохраненные процедуры или функции в пакеты?

    Нет. Это не обеспечивается в MySQL 5.1.

    5.6.7: Может сохраненная процедура вызывать другую сохраненную процедуру?

    Да.

    5.6.8: Может сохраненная процедура вызывать триггер?

    Сохраненная процедура может выполнять инструкцию SQL, типа UPDATE, которая вызывает триггер.

    5.6.9: Может сохраненная процедура обращаться к таблицам?

    Да. Сохраненная процедура может обращаться к таблицам.

    5.6.10: Может сохраненная процедура выдать ошибку прикладной программы?

    В MySQL 5.1 нет. Предполагается выполнять стандартные SQL-инструкции SIGNAL и RESIGNAL в будущем.

    5.6.11: Может сохраненная процедура обеспечивать обработку особых ситуаций?

    MySQL осуществляет определения HANDLER согласно стандарту SQL.

    5.6.12: Может сохраненная процедура в MySQL 5.1 вернуть набор результатов?

    Сохраненная процедура может, а вот сохраненная функция нет. Если Вы выполняете обычный SELECT внутри сохраненной процедуры, набор результатов возвращен непосредственно пользователю. Вы должны использовать клиент-серверный протокол MySQL 4.1 (или выше), чтобы это сработало. Это означает, что например, в PHP Вы должны использовать расширение mysqli вместо mysql.

    5.6.13: WITH RECOMPILE обеспечивается для сохраненных процедур?

    В MySQL 5.1 нет.

    5.6.14: Есть ли в MySQL аналог mod_plsql как шлюза к Apache, чтобы общаться непосредственно с сохраннеными процедурами в базе данных?

    Не имеется никакого эквивалента в MySQL 5.1.

    5.6.15: Я могу передавать массив как ввод сохраненной процедуре?

    В MySQL 5.1 нет.

    5.6.16: Я могу передавать курсор как параметр IN для сохраненной процедуры?

    В MySQL 5.1 курсоры доступны только внутри сохраненных процедур.

    5.6.17: Я могу возвращать курсор как параметр OUT из сохраненной процедуры?

    В MySQL 5.1 курсоры доступны только внутри сохраненных процедур. Однако, если Вы не открываете курсор на SELECT, результат будет послан непосредственно пользователю. Вы можете также применить SELECT INTO в переменные.

    5.6.18: Я могу распечатывать значение переменной внутри сохраненной подпрограммы для целей отладки?

    Да, Вы можете делать это в сохраненной процедуре, но не в сохраненной функции. Если Вы выполняете обычный SELECT внутри сохраненной процедуры, набор результатов возвращен непосредственно пользователю. Вы должны будете использовать протокол MySQL 4.1 (или выше). В PHP Вы должны использовать расширение mysqli вместо mysql.

    5.6.19: Я могу передавать или отменять транзакции внутри сохраненной процедуры?

    Да. Однако, Вы не можете выполнять транзакционные операции внутри сохраненной функции.

    молчанию: CONTAINS SQL, если никакаmysqlpro/storage.htm 600 0 0 220345 10643273210 10125 Глава 2. Типы памяти и таблиц

    Глава 2. Типы памяти и таблиц

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

    С MySQL 5.1 MySQL AB представил новую подключаемую архитектуру памяти, которая позволяет типам памяти загружаться и выгружаться по мере надобности. Если раньше приходилось перекомпилировать сервер, чтобы встроить поддержку соответствующего типа таблиц, теперь это не требуется.

    Эта глава описывает каждый из типов памяти MySQL, кроме NDB Cluster. Это также содержит описание новой архитектуры хранения.

    2.1. Краткий обзор архитектуры хранения данных в MySQL

    Архитектура хранения данных в MySQL позволяет профессионалу базы данных выбирать специализированный тип памяти для специфической потребности прикладной программы. Сервер MySQL изолирует прикладного программиста и DBA от всех подробностей реализации низкого уровня памяти, обеспечивая непротиворечивую и простую модель прикладной программы и API. Таким образом, хотя имеются различные возможности различных типов памяти, прикладная программа ограждена от этих различий.

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

    Прикладной программист и DBA взаимодействует с базой данных MySQL через Connector API и сервисные уровни, которые стоят выше типов памяти. Если изменения прикладной программы вызывают необходимость сменить тип памяти, то не придется особо напрягаться.

    2.1.1. Общий уровень сервера базы данных

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

    Чем вообще отличаются типы памяти? Основные отличия включают:

    • Concurrency: некоторые прикладные программы имеют более гранулированные требования блокировки (типа блокировок уровня строки) чем другие. Выбор правильной блокирующей стратегии может уменьшать непроизводительные затраты и, следовательно, улучшать полную эффективность. Эта область также включает поддержку возможностей типа многоверсионного управления параллелизма или предоставления кадра чтения.

    • Transaction Support: не каждая прикладная программа нуждается в транзакциях, но для тех, которым это надо, имеются очень хорошо определенные требования типа совместимости с ACID.

    • Referential Integrity: иногда надо, чтобы сервер в реляционной базе данных поддерживал справочную целостность через DDL-определенные внешние ключи.

    • Physical Storage: это включает все от полного размера страницы для таблиц и индексов до формата, используемого для сохранения данных на физический диск.

    • Index Support: различные прикладные программы имеют тенденцию извлекать пользу из различных индексных cтратегий. Каждый тип памяти вообще имеет собственные методы индексации, хотя некоторые (типа индексов B-tree) общие на почти всех типах.

    • Memory Caches: различные прикладные программы лучше отвечают одним кэширующим cтратегиям, чем другим, хотя некоторые кэши памяти общие на всех типах хранения.

    • Performance Aids: это включает многократные потоки ввода-вывода для параллельных операций, параллелизма потоков, введения контрольных точек базы данных, объемной обработки вставки и тому подобных функций.

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

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

    2.1.2. Съемная архитектура памяти

    В MySQL 5.1 MySQL AB представила новую съемную архитектуру памяти, которая позволяет загружать и выгружать типы памяти (ранее известные как драйверы таблиц) по мере надобности, не перезапуская сервер.

    2.1.2.1. Подключение типа памяти

    Прежде, чем тип памяти сможет использоваться, сменная общедоступная библиотека должна быть загружена в MySQL используя инструкцию INSTALL PLUGIN. Например, если сменный тип памяти EXAMPLE называется ha_example, а общедоступная библиотека именована ha_example.so, то Вы загружаете это следующей инструкцией:

    INSTALL PLUGIN ha_example SONAME 'ha_example.so';
    

    Общедоступная библиотека должна быть размещена в каталоге для сменных модулей сервера MySQL, расположение которого задано переменной системы plugin_dir.

    2.1.2.2. Отключение типа памяти

    Чтобы отключить тип памяти, используйте инструкцию UNINSTALL PLUGIN:

    UNINSTALL PLUGIN ha_example;
    

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

    2.1.2.3. Безопасность и сменные типы памяти

    Чтобы устанавливать съемный тип памяти, сменный файл должен быть размещен в сменном каталоге MySQL, а пользователь, выдающий инструкцию INSTALL PLUGIN должен иметь привилегию INSERT для таблицы mysql.plugin.

    2.2. Обеспечиваемые типы памяти

    MySQL 5.1 поддерживает следующие типы памяти:

    • MyISAM: применяемый по умолчанию тип памяти MySQL, который наиболее используется в Web, хранилищах данных и других средах прикладных программ. MyISAM обеспечивается во всех конфигурациях MySQL. Описан в книге "Руководство администратора СУБД MYSQL", глава 7, раздел "7.1 Таблицы MyISAM".

    • InnoDB: использован для прикладных программ диалоговой обработки запросов и ряда свойств, включая поддержку транзакций ACID и внешние ключи. InnoDB включен по умолчанию во все двоичные дистрибутивы MySQL 5.1. Описан в книге "Руководство администратора СУБД MYSQL", глава 7, раздел "7.6 Таблицы InnoDB".

    • Falcon: работает с многократными потоками и безопасной средой транзакции, которая безопасно хранит данные при обеспечении весьма высокой производительности.

      ПРЕДУПРЕЖДЕНИЕ: Falcon в настоящее время обеспечивается только внутри ветки MySQL 5.1 и не рассматривается готовым к выпуску. Это обеспечивается только для целей тестирования и оценки на этой стадии.

    • Memory: сохраняет все данные в RAM для чрезвычайно быстрого доступа в средах, которые требуют быстрых поисковых таблиц. Этот тип памяти был прежде известен как HEAP. Описан в книге "Руководство администратора СУБД MYSQL", глава 7, раздел " 7.4 Таблицы HEAP".

    • Merge: позволяет MySQL DBA или разработчику логически группировать ряд идентичных MyISAM-таблиц и ссылаться на них как на один объект. Хороши для VLDB-сред, типа хранилищ данных. Описан в книге "Руководство администратора СУБД MYSQL", глава 7, раздел " 7.2 Таблицы MERGE".

    • Archive: обеспечивает совершенное решение для сохранения и восстановления больших количеств редко используемых исторических, архивированных данных.

    • Federated : предлагает способность связать отдельные серверы MySQL, чтобы создать одну логическую базу данных из многих физических. Очень хорош для распределенной среды данных.

    • NDB Cluster (он же NDB): кластерный вариант базы данных, который особенно подходит для прикладных программ с высокоэффективными потребностями поисковой таблицы, которые также требуют самой высокой возможной степени полезного времени и доступности. Описан подробно в моей работе " MySQL Cluster".

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

    • Blackhole : принимает к записи, но не сохраняет данные, а поиски всегда возвращают пустой набор. Функциональные возможности могут использоваться в распределенном проекте базы данных, где данные автоматически скопируются, но не сохранены локально.

    • Example: это тип памяти, который не делает ничего. Вы можете создавать таблицы с ним, но никакие данные не могут быть сохранены в них или восстановлены из них. Цель этого типа памяти в том, чтобы служить примером того, как вообще надо писать типы памяти. Это прежде всего представляет интерес для разработчиков.

    Эта глава описывает каждый из типов памяти MySQL, кроме MySQL Cluster.

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

    2.2.1. Выбор типа памяти

    Различные типы памяти, обеспеченные MySQL, разработаны для различных случаев использования. Чтобы использовать съемную архитектуру памяти, хорошо иметь представление относительно выгод и недостатков различных типов памяти (хранения). Следующая таблица обеспечивает краткий обзор некоторых вариантов, обеспеченных MySQL:

    Свойство MyISAM Memory InnoDB Archive NDB
    Ограничения памяти256 TBДа64TB Нет384 EB[4]
    ТранзакцииНетНетДаНет Да
    Блокировка степени детализацииТаблицаТаблица СтрокаСтрокаСтрока
    MVCC (кадр чтения)НетНетДа ДаНет
    ГеографияДаНетДа[1] Да[1]Да[1]
    Индексы B-treeДаДаДа НетДа
    Hash-индексыНетДаНетНет Да
    Поисковые индексы Full-textДаНетНет НетНет
    Индексы для кластераНетНетДа НетНет
    Кэширование данныхНетНе определеноДа НетДа
    Кэширование индексовДаНе определеноДа НетДа
    Сжатие данныхДаНетНетДа Нет
    Шифрование данных[2]ДаДа ДаДаДа
    ClusterНетНетНет НетДа
    Репликация[3]ДаДа ДаДаДа
    Поддержка внешнего ключаНетНетДа НетНет
    Копия / восстановление на момент времени[3] ДаДаДаДаДа
    Поддержка кэша запросовДаДаДа ДаДа
    Модификация статистики для словаря данныхДаДа ДаДаДа

    Некоторые необходимые пояснения:

    • [1] Поддерживает пространственные типы данных, но не выполняет индексацию таких данных.

    • [2] Выполнено в сервере (через функции шифрования), а не в типе памяти.

    • [3] Выполнено в сервере, а не в типе памяти.

    • [4] EB = exabyte (экзабайт = 1024 * 1024 терабайт).

    2.2.2. Сравнение транзакционных и не транзакционных таблиц

    Транзакционно-безопасные таблицы (TST) имеют несколько преимуществ над не транзакционно-безопасными таблицами (NTST):

    • Они более надежные. Даже если MySQL терпит крах, или Вы получаете аппаратные проблемы, Вы можете получить Ваши данные обратно автоматическим восстановлением или из копии плюс файл регистрации транзакции.

    • Вы можете объединять много инструкций и принимать их все в то же самое время инструкцией COMMIT (если autocommit выключен).

    • Вы можете выполнять ROLLBACK, чтобы игнорировать Ваши изменения (если autocommit выключен).

    • Если произошел сбой модификации, все Ваши изменения вернутся. С не транзакционно-безопасными таблицами все изменения, которые имели место, постоянны.

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

    Вы можете объединять транзакционно-безопасные и не транзакционно-безопасные таблицы в тех же самых инструкциях. Однако, хотя MySQL поддерживает несколько транзакционно-безопасных типов памяти (хранения), для самых лучших результатов, Вы не должны смешивать различные типы внутри транзакции с заблокированным autocommit. Например, если Вы делаете это, изменения для не транзакционно-безопасной таблицы все еще совершены немедленно и не могут быть прокручены обратно.

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

    • Намного быстрее.

    • Более низкие требования дискового пространства.

    • Меньшее количество памяти требуется, чтобы выполнить модификации.

    2.2.3. Другие типы памяти

    Другие типы памяти могут быть доступны от третьих лиц, которые использовали Custom Storage Engine interface.

    Вы можете находить подробную информацию в списке типов памяти третьего лица на странице MySQL Forge Storage Engines http://forge.mysql.com/projects/search.php?t=tag&k=storage%20engine.

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

    На текущий момент есть следующие сторонние типы памяти:

    • PrimeBase XT (PBXT): PBXT был разработан для современного web-основанного параллелизма.

    • RitmarkFS RitmarkFS позволяет Вам обращаться и управлять файловой системой, используя SQL-запросы. RitmarkFS также поддерживает репликацию файловых систем и трэкинг изменений.

    • Distributed Data Engine: Open Source проект, который специализирован, чтобы обеспечить поддержку распределенных данных согласно статистике рабочей нагрузки.

    • mdbtools: съемный тип памяти, который позволяет доступ только для чтения к .mdb-файлам базы данных Microsoft Access.

    • solidDB for MySQL разработан для задание-критических реализаций, которые требуют транзакционные базы данных. solidDB многопоточный драйвер, который полностью поддерживает ACID со всеми ожидаемыми уровнями изоляции транзакции, блокировкой уровня строки и многоверсионным управлением параллелизма (MVCC) с не блокируемыми чтением и записью.

    Для подробной информации относительно разработки типа памяти, который может использоваться со съемной архитектурой памяти обратитесь к Writing a Custom Storage Engine в MySQL Internals.

    2.3. Установка типа памяти

    Когда Вы создаете новую таблицу, Вы можете определять, который тип памяти использовать, добавляя опцию ENGINE к инструкции CREATE TABLE:

    CREATE TABLE t (i INT) ENGINE = INNODB;
    

    Если Вы опускаете опцию ENGINE или TYPE, используется заданный по умолчанию памяти. Обычно это MyISAM, но Вы можете изменять это, используя опцию сервера --default-storage-engine или --default-table-type, либо устанавливая опцию default-storage-engine или default-table-type в файле конфигурации my.cnf.

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

    SET storage_engine=MYISAM;
    

    Когда MySQL установлен на Windows, используя MySQL Configuration Wizard, InnoDB может быть выбран как значение по умолчанию вместо MyISAM.

    Чтобы преобразовывать таблицу из одного типа памяти в другой, используйте инструкцию ALTER TABLE, которая указывает новый тип памяти:

    ALTER TABLE t ENGINE = MYISAM;
    

    Если Вы пробуете использовать тип памяти, который не компилируется в сервер (или компилируется, но дезактивирован), MySQL взамен создает таблицу, использующую заданный по умолчанию тип памяти, обычно MyISAM. Это поведение удобно, когда Вы хотите копировать таблицы между серверами MySQL, которые поддерживают различные типы памяти.

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

    Для новых таблиц MySQL всегда создает .frm-файл, чтобы сохранить определения столбцов и таблицу. Индекс таблицы и данные может быть сохранен в одном или большем количестве других файлов, в зависимости от типа памяти. Сервер создает .frm-файл выше уровня типа памяти. Индивидуальные типы создают любые дополнительные файлы, требуемые для таблиц, с которыми они управляются. Если имя таблицы содержит специальные символы, имена для файлов таблицы содержат закодированные версии тех символов. База данных может содержать таблицы различных типов. То есть, не все таблицы должны быть созданы с тем же самым типом памяти.

    2.4. Тип памяти Falcon

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

    Предупреждение

    Falcon в настоящее время Alpha-релиз и не должен использоваться в промышленных средах. Falcon в настоящее время обеспечивается только внутри ветви MySQL 5.1 и не рассматривается готовым. Это обеспечивается только для целей оценки и тестирования. Обратите внимание, что MySQL 5.1 Falcon не может включать все ошибки или свойства, которые применяются к главному дереву 5.1.

    Falcon в настоящее время доступен только для 32-разрядной Windows и 32 или 64-разрядной Linux. Дополнительные платформы будут добавлены после alpha-версии.

    2.4.1. Свойства Falcon

    Falcon был разработан для систем, которые способны поддерживать большую память и многопоточные или мультиядерные среды CPU. Большинство 64-битных систем представляют собой идеальные платформы для Falcon, где имеется большое доступное пространство памяти и 2, 4 или 8-ядерные CPU. Это также может быть развернуто внутри стандартной 32-разрядной среды.

    Falcon поддерживает ряд главных особенностей, которые делают возможным его применение в среде с большими нагрузками:

    • Multi Version Concurrency Control (MVCC) дает возможность записям и таблицам модифицироваться без непроизводительных затрат, связанных с блокировками уровня строки. Реализация MVCC фактически устраняет потребность блокировать таблицы или строки в течение процесса модификации.

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

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

    • Transaction-safe (полностью совместим с ACID) и способен обрабатывать многократные параллельные транзакции.

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

    • Продвинутые индексы B-Tree.

    • Сервер предписывает справочную целостность и всегда гарантирует проверку правильности данных.

    • Сжатие данных сохраняет информацию на диск в сжатом формате, сжимая и декомпрессируя данные на лету. Результат в меньших и более эффективных физических размерах данных.

    • Интеллектуальное дисковое управление автоматически управляет размером файла на диске, расширениями и восстановлением места.

    • Данные и индексное кэширование обеспечивают быстрый доступ к данным без требования загрузить индексные данные с диска.

    • Неявные точки сохранения гарантируют целостность данных в течение транзакций.

    2.4.2. Параметры конфигурации

    Параметры конфигурированы через стандартный файл my.cnf или my.ini. Параметры могут быть конфигурированы, определяя имя параметра и соответствующее значение через пробел. Значения Memory могут быть определены в байтах или числом, сопровождаемым kb, mb или gb.

    • falcon_min_record_memory (Record Cache Base) устанавливает минимальный объем памяти, который будет распределен для кэширования данных при записи. Когда кэш-память убирает мусор, процесс остановится, пока использование кэша не достигнет этого значения. Значение по умолчанию: falcon_max_record_memory/2 (10 MB).

    • falcon_max_record_memory (Record Cache Top) устанавливает максимальный размер памяти, которая будет распределена для кэширования данных при записи. Значение по умолчанию 20 MB.

    • falcon_page_cache_size (Page Cache Size) устанавливает объем памяти, который будет распределен для кэширования страниц из файла пространства таблицы. Значение по умолчанию 4 MB.

    Связь между кэшем записи и кэшем страницы управляется информацией, которая кэшируется каждой системой. Целые записи, которые находятся в активном использовании (читаемые или модифицируемые) сохранены внутри кэша записи, однако, данные BLOB сохранены только внутри кэша страницы.

    Кэш страницы используется, чтобы сохранить метаданные базы данных, данные BLOB и индексы таблицы.

    Параметры Falcon также могут быть установлены в командной строке mysqld через использование следующих параметров командной строки:

    • --falcon-max-record-memory=#

    • --falcon-min-record-memory=#

    • --falcon-page-cache-size=#

    Вы можете также допускать и отключать тип памяти Falcon при запуске, обеспечивая эти параметры mysqld, если этот mysqld включает тип памяти Falcon:

    • --falcon включает Falcon.

    • --skip-falcon выключает Falcon.

    2.4.3. Создание пространства таблиц Falcon

    Внутри Falcon все данные внутри одной базы данных сохранены внутри одиночного пространства таблиц, которое в свою очередь сохранено внутри одного файла в структуре каталогов MySQL. Одиночная база данных Falcon создаст три главных файла. Один файл содержит данные Falcon и будет сохранен в файле с именем базы данных Falcon с расширением .fts. Например, таблицы Falcon определенные в базе данных test, будут сохранены внутри файла test.fts в каталоге баз данных MySQL.

    Два других файла содержат дисковую копию последовательного файла регистрации Falcon. Они также созданы внутри области соответствующей базы данных. В будущем выпуске Вы сможете определить альтернативное расположение для этих журналов. Так с вышеупомянутым файлом данных примера test.fts журналы будет именованы test.fl1 и test.fl2.

    Определения таблицы, как с другими типами памяти MySQL, сохранены в файл .frm в каталоге базы данных. Например, таблица falcontest в базе данных test создаст файл определения (описания) таблицы falcontest.frm в каталоге test.

    При создании таблицы внутри базы данных MySQL, где соответствующий файл пространства таблиц Falcon не существует, это будет автоматически создано с файлом данных и журналами.

    2.4.4. Создание таблиц и индексов в Falcon

    Falcon поддерживает все стандартные типы данных столбцов, обеспечиваемые MySQL.

    Чтобы создать таблицу, которая использует Falcon, примените опцию ENGINE = Falcon в инструкции CREATE TABLE:

    CREATE TABLE names (id INT, fname VARCHAR (20),
                        lname VARCHAR (20)) ENGINE=Falcon
    

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

    CREATE TABLE ids (id int, index (id)) ENGINE=Falcon
    

    Генерируйте один как часть первичного ключа:

    CREATE TABLE ids (id int),PRIMARY KEY (id) ENGINE=Falcon
    

    Или Вы можете создавать много ключей и многократные индексы:

    CREATE TABLE t1 (id int NOT NULL, id2 int NOT NULL, id3 int NOT NULL,
                     name CHAR(30), primary key (id, id2),
                     index index_id3 (id3)) ENGINE=Falcon
    

    2.4.5. Принципы и терминология

    Вы должны понять следующие базисные принципы и терминологию.

    MySQL Falcon объединяет продвинутые методы с упрощенной структурой, которая приводит к высокоэффективной транзакционной базе данных, которая требует небольшого сопровождения или поиска неисправностей администратором базы данных.

    • Файл данных пользователя сохраняет данные Falcon.

    • Последовательный файл регистрации Falcon содержит недавно совершенные изменения данных, индексные изменения и транзакционную информацию. Также обеспечивает средства восстановления данных.

    • Кэш страницы хранит страницы базы данных.

    • Кэш записи хранит копии активных и нейтральных записей.

    • Память системы хранит информацию контекста транзакции, индексные акселераторы и метаданные системы.

    • Рабочие потоки являются фоновыми потоками. Имеются два потока: поток "gopher" перемещает данные из последовательный файла регистрации Falcon в кэш страницы базы данных и из кэша страниц на диск. Второй поток программы записи страницы, который пишет страницы с blob.

    2.4.5.1. Файл и структуры данных Falcon

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

    Страницы описывают блок распределения оперативной памяти в Falcon. Страницы используются, чтобы сохранить данные и индексировать информацию. Размер страницы и то, как Falcon кэширует и распределяет страницы для использования при сохранении информации, воздействует на эффективность в зависимости от записей, которые сохраняются.

    Страницы, кэшируемые в памяти используются, чтобы сохранить индексы, blob'ы и структурные данные для конкретного пространства таблиц. Активные записи сохранены внутри отдельного кэша записей.

    Все транзакции в базе данных регистрируются и сохранены внутри отдельного журнала. Журнал автоматически сбрасывается и изменения записываются на диск, когда имеется команда COMMIT, когда включен auto-commit или автоматически через каждые 30 секунд, когда транзакции не используются.

    2.4.5.2. Последовательный файл регистрации Falcon

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

    • Записи данных в течение совершающейся фазы.

    • Физические изменения базы данных, требуемые для восстановления данных после аварийного отказа.

    • Логические изменения базы данных, требуемые для восстановления ресурса после аварийного отказа.

    • Изменения статуса для всех активных транзакций.

    Все транзакции в Falcon записаны в последовательный файл регистрации Falcon, а затем переданы к базе данных автоматически, если включен AUTOCOMMIT, или вручную, когда используется команда COMMIT.

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

    Обратите внимание, однако, что последовательный файл регистрации только модифицирует данные записи через кэш страницы в оперативной памяти. Фактические данные записи будут записаны на диск, когда происходит процесс контрольной точки. Исключительная ситуация к этому правилу: индексные и blob-записи, которые немедленно записаны на диск как часть процесса.

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

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

    2.4.5.2.1. Процесс обратной перемотки

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

    • Отступающие индексные модификации.

    • Отменяет любые данные blob, созданные транзакцией.

    • Освобождает распределенные слоты записи.

    • Отменяет версию записи, созданную в памяти.

    2.4.5.2.2. Групповое завершение транзакций

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

    1. Транзакция 1 создает все необходимые входы файла регистрации и начинает записывать файл регистрации на диск.

    2. В то время как транзакция 1 завершается, транзакции 2 и 3 записывают их входы в последовательный файл регистрации.

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

    4. В то время как транзакции 2 и 3 записывают, транзакции 4, 5 и 6 записываются в журнал в оперативной памяти. Когда запись для 2 и 3 завершается, входы для 4, 5 и 6 записаны.

    Результат вышеупомянутого процесса: имеются только три физические записи на диск, даже при том, что имеется шесть транзакций в последовательности:

    • Транзакция 1,

    • Транзакции 2 и 3,

    • Транзакции 4, 5 и 6.

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

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

    2.4.5.3. Восстановление аварийного отказа Falcon

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

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

    2.4.5.4. Кэши памяти Falcon

    Falcon был разработан, чтобы выполняться лучше всего на системах с щедрыми объемами памяти. Кэши памяти, используемые Falcon подобны в некоторых отношениях другим СУБД и MySQL. Однако, структура кэш имеет ряд усовершенствований по сравнению с традиционной cтратегией кэширующей памяти. Механизмы, используемые Falcon относительно кэширования памяти включают:

    • Log Cache информация файла регистрации сохраняется в памяти и сбрасывается на диск, когда транзакции совершаются. Falcon хранит восемь окон для чтения и записи в журнал, и каждое окно 1 MB.

    • System and Index Cache данные, необходимые Falcon (определения таблицы и полей, состояние транзакции и т.д.) также поддерживаются в памяти для справочника. Кроме того, локальные индексные акселераторы представляют индексные сегменты, созданные выполняющейся транзакцией, также сохранены в памяти системы. Когда транзакция изменяет индексированные поля, это формирует индексный раздел акселератора в памяти системы, представляя изменения. При завершении транзакции все индексные измене ния для транзакции записаны в сортируемом порядке в последовательный вход и позже объединены с постоянным индексом.

    • Page Cache страницы базы данных читаются с диска для специфической базы данных. Размер кэша страницы управляется параметром falcon_page_cache_size, значение по умолчанию которого 4 MB установлено в файле my.cnf. Хотя изменения записи и индекса идут в последовательный файл регистрации прежде, чем запишутся в страницы базы данных, данные blob записаны непосредственно в кэш страницы. Это не дает регистрировать большие элементы данных, которые редко вызваны или изменены транзакцией, которая создает их.

    • Record Cache кэш записи представляет собой область памяти в зоне ожидания строк, которые были запрошены запросами конечного пользователя для специфической базы данных или созданы активными транзакциями. Обратите внимание, что этот кэш отличается от традиционных кэшей данных тем, что только специфические строки, необходимые прикладным программам, постоянно находятся в кэше в противоположность всем данным страницы (которая может содержать только подмножества необходимой информации). Кэш записи может хранить несколько версий записей, которые изменились или удалены. Эта методика гарантирует, что активные данные, необходимые, чтобы удовлетворять запросы пользователя находятся в памяти, сокращают время доступа к строке и уменьшают кэш, не включая незапрошенную информацию. Кэш записи также помогает в обеспечении механизм многоверсионного управления параллелизма (MVCC). Кэш записи управляется двумя параметрами. Параметр falcon_min_record_memory (заданный по умолчанию в 10 MB) определяет минимальное количество RAM, обеспеченной кэшу записи, а falcon_max_record_memory (заданный по умолчанию в 20 MB) ограничивает общую сумму памяти, доступной кэшу.

    • Из-за поддержки кэша записи транзакциями, используется поток-мусоросборщик, чтобы гарантировать только горячие данные постоянно находятся в кэше. Когда ограничение falcon_max_record_memory достигнуто, Falcon рассматривает демографию данных в кэше и удаляет самые старые поколения. Этот процесс более усложнен, чем стандартный алгоритм LRU, используемый многими системами баз данных, но это более эффективно и быстро.

    2.4.5.5. Потоки Falcon

    Falcon использует два рабочих потока, чтобы обработать информацию внутри структур Falcon. Один поток посвящен перемещению совершенных изменений данных из файла регистрации на страницы и объединению индексных изменений с постоянными индексными данными. Второй обрабатывает периодический сброс кэша страницы и убирает мусор, распределенный внутри кэша записи.

    2.4.5.6. Сжатие данных

    Данные, сохраненные в пространстве таблиц Falcon сжаты на диске, но сохранены в несжатом формате в памяти. Сжатие происходит автоматически, когда данные переданы на диск.

    2.4.5.7. Слот записи

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

    2.4.6. Ограничения

    Имеется ряд ограничений в alpha-версии Falcon. В дальнейшем они постепенно будут сниматься:

    • Не работает SELECT FOR UPDATE.

    • Для Alpha-версии максимальная длина ключа ограничена 1100 байтами.

    • Уровни изоляции Serializable не обеспечиваются.

    • Конфигурация времени ожидания для блокировки не обеспечивается.

    • Распределенные транзакции не обеспечиваются.

    • Имеется ограничение 232 (4.29 миллиарда) строк для одиночной таблицы. Используя много таблиц внутри того же самого пространства таблиц Вы можете иметь больше, чем это число записей. В будущем выпуске это ограничение будет удалено.

    • Размеры страницы с перестраиваемой конфигурацией не обеспечиваются, но запланированы на будущий выпуск.

    • Таблицы Falcon могут поддерживать до 32000 столбцов.

    • Каждое пространство таблиц имеет ограничение в 232 страниц внутри одиночного пространства. Через комбинацию размера страницы и максимального числа страниц имеется ограничение 140737488355328 байт (128 TB) одиночного пространства таблиц.

    • Интерактивное резервирование не обеспечивается, но поддержка запланирована в будущем выпуске.

    • Поддержка внешнего ключа в настоящее время недоступна.

    Хотя максимальная доступная память внутри пространства таблиц 128 TB, истинное число записей и объем данных, которые Вы можете сохранять, зависит от ряда факторов:

    • Требования памяти записью.

    • Индексные требования памяти.

    • Коэффициент сжатия сохраненных данных.

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

    2.5. Тип памяти EXAMPLE

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

    Тип памяти EXAMPLE включен в двоичные дистрибутивы MySQL-Max. Чтобы его включить, если Вы формируете MySQL из исходного текста, вызовите configure с опцией --with-example-storage-engine.

    Чтобы исследовать исходник типа памяти EXAMPLE, смотрите каталог storage/example исходных текстов MySQL.

    Когда Вы создаете таблицу типа EXAMPLE, сервер честно создает файл формата таблицы в каталоге баз данных. Имя файла начинается с имени таблицы и имеет расширение .frm. Никакие другие файлы не созданы. Никакие данные не могут быть сохранены в таблицу. Запросы возвращают пустой результат:

    mysql> CREATE TABLE test (i INT) ENGINE = EXAMPLE;
    Query OK, 0 rows affected (0.78 sec)
    mysql> INSERT INTO test VALUES(1),(2),(3);
    ERROR 1031 (HY000): Table storage engine for 'test' doesn't ┬╗
                        have this option
    mysql> SELECT * FROM test;
    Empty set (0.31 sec)
    

    Тип EXAMPLE не поддерживает индексацию.

    2.6. Тип памяти FEDERATED

    Тип памяти FEDERATED обращается к данным в таблицах удаленных баз данных, а не в локальных таблицах.

    Тип памяти FEDERATED включен в двоичные дистрибутивы MySQL-Max. Чтобы его включить, если Вы формируете MySQL из исходного текста, вызовите configure с опцией --with-federated-storage-engine.

    Чтобы исследовать исходник типа памяти FEDERATED, смотрите каталог sql исходных текстов MySQL.

    Дополнительные ресурсы:

    2.6.1. Описание типа памяти FEDERATED

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

    Для локальных таблиц базы данных файлы данных локальны. Например, если Вы создаете MyISAM-таблицу с именем users, драйвер MyISAM создает файл данных, именованный users.MYD. Драйвер для локальных таблиц читает, вставляет, удаляет и модифицирует данные в локальных файлах данных, и строки сохранены в частном формате драйвера. Чтобы читать строки, драйвер должен анализировать данные в столбцах. Чтобы записывать строки, значения столбцов должны быть преобразованы в формат строки, используемый драйвером и записаны в локальный файл данных.

    А вот в типе памяти FEDERATED не имеется никаких локальных файлов данных для таблицы (например, нет файла .MYD). Вместо этого удаленная база данных сохраняет данные, которые обычно были бы в таблице. Локальный сервер соединяется с удаленным и использует клиентское API MySQL, чтобы читать, удалять, модифицировать и вставлять данные в удаленной таблице. Поиск данных инициализирован через инструкции SQL SELECT * FROM tbl_name. Чтобы читать результат, строки выбраны по одной, используя функцию C API mysql_fetch_row(), а затем преобразуя столбцы в наборе результатов SELECT к формату, который ожидает получить драйвер FEDERATED.

    Поток информации таков:

    1. SQL-обращения выданы локально.

    2. Используется MySQL handler API (данные в формате драйвера).

    3. Клиентский API MySQL (данные преобразованы в обращения SQL).

    4. Удаленная база данных -> клиентский API MySQL.

    5. Конвертация набора результатов (если надо) к формату драйвера.

    2.6.2. Как использовать таблицы FEDERATED

    Процедура для использования таблиц FEDERATED очень проста. Обычно Вы имеете два выполняемых сервера. В принципе возможно использовать другую таблицу, которая управляется тем же самым сервером, хотя имеются некоторые хитрости при этом.

    Сначала Вы должны иметь таблицу на удаленном сервере, к которой Вы хотите обращаться, используя таблицу FEDERATED. Предположите, что удаленная таблица находится в базе данных federated и определена подобно этому:

    CREATE TABLE test_table (id INT(20) NOT NULL AUTO_INCREMENT,
                             name VARCHAR(32) NOT NULL DEFAULT '',
                             other INT(20) NOT NULL DEFAULT '0', PRIMARY KEY(id),
                             INDEX name (name), INDEX other_key (other))
                             ENGINE=MyISAM DEFAULT CHARSET=latin1;
    

    Пример использует таблицу MyISAM, но таблица могла бы использовать любой тип памяти.

    Затем создайте таблицу FEDERATED на локальном сервере для доступа к удаленной таблице:

    CREATE TABLE federated_table (id INT(20) NOT NULL AUTO_INCREMENT,
                                  name VARCHAR(32) NOT NULL DEFAULT '',
                                  otherINT(20) NOT NULL DEFAULT '0',
                                  PRIMARY KEY(id), INDEX name (name),
                                  INDEX other_key (other)) ENGINE=FEDERATED
                                  DEFAULT CHARSET=latin1
           CONNECTION='mysql://root@remote_host:9306/federated/test_table';
    

    Обратите внимание: CONNECTION заменяет COMMENT, используемый в некоторых предыдущих версиях MySQL.

    Структура этой таблицы должна быть точно такая же, как у удаленной таблицы, за исключением того, что опция ENGINE таблицы должна быть FEDERATED, а опция таблицы CONNECTION задает строку подключения, которая указывает для драйвера FEDERATED, как соединиться с удаленным сервером.

    Тип памяти FEDERATED создает только файл test_table.frm в базе данных federated.

    Удаленная информация хоста указывает удаленный сервер, с которым Ваш локальный соединяется, а база данных и информация таблицы указывают, которую удаленную таблицу использовать как источник данных. В этом примере удаленный сервер обозначен как remote_host (порт 9306), так что на удаленной системе должен быть сервер MySQL, слушающий порт 9306.

    Общая форма строки подключения в опции CONNECTION такова:

    scheme://user_name[:password]@host_name
    [:port_num]/db_name/tbl_name
    

    Только mysql обеспечивается как значение scheme в этот момент, пароль и номер порта факультативны.

    Имеются некоторые примеры строк подключения:

    CONNECTION='mysql://username:password@hostname:port/database/tablename'
    CONNECTION='mysql://username@hostname/database/tablename'
    CONNECTION='mysql://username:password@hostname/database/tablename'
    

    Использование CONNECTION для определения строки подключения не оптимально и, вероятно, измениться в будущем.

    Потому что любой пароль, заданный в строке подключения, сохранен как простой текст, он может быть замечен любым пользователем, который может применить SHOW CREATE TABLE или SHOW TABLE STATUS для таблицы FEDERATED или сделать запрос таблицы TABLES в базе данных INFORMATION_SCHEMA.

    2.6.3. Ограничения типа памяти FEDERATED

    Далее перечислены свойства, которые FEDERATED не поддерживает:

    • В первой версии удаленный сервер должен быть MySQL-сервером. Поддержка FEDERATED для других СУБД может быть добавлена в будущем.

    • Удаленная таблица, на которую указывает таблица FEDERATED, ДОЛЖНА существовать прежде, чем Вы попробуете обращаться к ней через драйвер FEDERATED.

    • Возможно для одной таблицы FEDERATED указывать на другую, но Вы должны быть внимательны, чтобы не создать цикл.

    • Не имеется никакой поддержки транзакций.

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

    • FEDERATED понимает SELECT, INSERT, UPDATE, DELETE и индексы. Это не поддерживает ALTER TABLE или любые инструкции Data Definition Language, кроме DROP TABLE. Текущая реализация не использует подготовленные инструкции.

    • Любая инструкция DROP TABLE, выданная для таблицы FEDERATED, удалит только локальную таблицу, но не удаленную.

    • Реализованы SELECT, INSERT, UPDATE и DELETE, но не HANDLER.

    • Таблицы FEDERATED не работают с кэшем запроса.

    Некоторые из этих ограничений могут сниматься в будущих версиях драйвера FEDERATED.

    2.7. Тип памяти ARCHIVE

    Тип памяти ARCHIVE используется для сохранения больших количеств данных без индексов в очень маленьком файле.

    Тип памяти ARCHIVE включен в двоичные дистрибутивы MySQL. Чтобы его включить, если Вы формируете MySQL из исходного текста, вызовите configure с опцией --with-archive-storage-engine.

    Чтобы исследовать исходник типа памяти ARCHIVE, смотрите каталог storage/archive исходных текстов MySQL.

    Вы можете проверять, является ли доступным тип памяти ARCHIVE этой инструкцией:

    mysql> SHOW VARIABLES LIKE 'have_archive';
    

    Когда Вы создаете таблицу типа ARCHIVE, сервер создает файл формата таблицы в каталоге баз данных. Имя файла начинается с имени таблицы и имеет расширение .frm. Драйвер памяти создает и другие файлы, имена коих начинаются с имени таблицы. Данные и файлы метаданных имеют расширения .ARZ и .ARM, соответственно. Файл .ARN может появляться при операциях оптимизации.

    Драйвер типа памяти ARCHIVE понимает INSERT и SELECT, но не DELETE, REPLACE или UPDATE. Это поддерживает операции ORDER BY столбцы BLOB и в основном все, кроме пространственных, типы данных. Блокировка уровня строки использована в ARCHIVE.

    Начиная с MySQL 5.1.6, тип ARCHIVE поддерживает атрибут столбца AUTO_INCREMENT. Такие столбцы могут иметь уникальный или не-уникальный индекс. Попытка создавать индекс на любом другом столбце приводит к ошибке. Тип памяти ARCHIVE также поддерживает опцию таблицы AUTO_INCREMENT в CREATE TABLE и ALTER TABLE, чтобы определить начальное значение последовательности для новой таблицы или сбросить значение последовательности для существующей таблицы, соответственно.

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

    SELECT a, b, blob_col FROM archive_table;
    SELECT a, b FROM archive_table;
    

    Хранение: строки сжаты, когда они вставлены. Тип памяти ARCHIVE использует сжатие данных zlib без потерь (подробности на сайте http://www.zlib.net/). Вы можете использовать OPTIMIZE TABLE, чтобы анализировать таблицу и упаковывать ее в меньший формат (причины применения именно OPTIMIZE TABLE, изложены ниже). Тип памяти также поддерживает CHECK TABLE. Имеются несколько типов вставок, которые используются:

    • Инструкция INSERT только помещает строки в буфер сжатий, а буферные пишется по мере необходимости. Вставка в буфер защищена блокировкой. SELECT сбрасывает все данные на диск, если вставки не были INSERT DELAYED (такие сбрасываются по мере необходимости).

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

    Поиск: при поиске строки несжаты по требованию, не имеется никакого кэша строк. Операция SELECT выполняет полный просмотр таблицы. Когда происходит SELECT, это выясняет, сколько строк в настоящее время доступны, и читает это число строк. SELECT выполняется как непротиворечивое чтение. Обратите внимание, что большое количество инструкций SELECT в течение вставки может ухудшать сжатие, если только отсроченные вставки не используется. Чтобы достигать лучшего сжатия, Вы можете использовать OPTIMIZE TABLE или REPAIR TABLE. Число строк в таблицах ARCHIVE, сообщенное SHOW TABLE STATUS, всегда точно.

    Дополнительные ресурсы:

    2.8. Тип памяти CSV

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

    Чтобы включить этот тип памяти, используйте опцию --with-csv-storage-engine в скрипте configure при сборке MySQL.

    Тип памяти CSV включен в двоичные дистрибутивы MySQL-Max. Чтобы его включить, если Вы формируете MySQL из исходного текста, вызовите configure с опцией --with-csv-storage-engine. Чтобы исследовать исходник типа памяти CSV, смотрите каталог storage/csv исходных текстов MySQL.

    Когда Вы создаете таблицу CSV, сервер создает файл формата таблицы в каталоге баз данных. Имя файла начинается с имени таблицы и имеет расширение .frm. Тип памяти также создает файл данных. Имя его начинается с имени таблицы и имеет расширение .CSV. Файл данных представляет собой простой текстовый файл. Когда Вы сохраняете данные в таблицу, тип памяти сохраняет это в файл данных в разделяемом запятыми формате значений.

    mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = CSV;
    Query OK, 0 rows affected (0.12 sec)
    mysql> INSERT INTO test VALUES(1,'record one'),(2,'record two');
    Query OK, 2 rows affected (0.00 sec)
    Records: 2 Duplicates: 0 Warnings: 0
    
    mysql> SELECT * FROM test;
    +---+------------+
    | i | c          |
    +---+------------+
    | 1 | record one |
    | 2 | record two |
    +---+------------+
    2 rows in set (0.00 sec)
    

    Начиная с MySQL 5.1.9, при создании таблицы CSV также создается соответствующий метафайл, который сохраняет состояние таблицы и число строк, которые существуют в таблице. Имя этого файла такое же, как имя таблицы, но с расширением CSM.

    Если Вы исследуете файл test.CSV в каталоге баз данных созданный, выполняя предшествующие инструкции, его содержимое должно выглядеть следующим образом:

    "1","record one"
    "2","record two"
    

    Этот формат может читаться и даже записываться прикладными программами электронных таблицы типа Microsoft Excel или StarOffice Calc.

    2.8.1. Восстановление и проверка таблицы CSV

    Функциональные возможности, представленные в версии 5.1.9.

    Тип памяти CSV поддерживает команды CHECK и REPAIR, чтобы проверить и, если возможно, отремонтировать поврежденную таблицу CSV.

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

    mysql> check table csvtest;
    +--------------+-------+----------+----------+
    | Table        | Op    | Msg_type | Msg_text |
    +--------------+-------+----------+----------+
    | test.csvtest | check | status   | OK       |
    +--------------+-------+----------+----------+
    1 row in set (0.00 sec)
    

    Проверка на разрушенной таблице возвращает неисправность:

    mysql> check table csvtest;
    +--------------+-------+----------+----------+
    | Table        | Op    | Msg_type | Msg_text |
    +--------------+-------+----------+----------+
    | test.csvtest | check | error    | Corrupt  |
    +--------------+-------+----------+----------+
    1 row in set (0.01 sec)
    

    Если сбой проверки произошел, таблица отмечена как разрушенная. Если только таблица была отмечена как разрушенная, она будет автоматически восстановлена, когда Вы затем выполняете инструкцию CHECK или SELECT. Соответствующее разрушенное состояние и новое состояние будут отображаться при выполнении CHECK:

    mysql> check table csvtest;
    +--------------+-------+----------+----------------------------+
    | Table        | Op    | Msg_type | Msg_text                   |
    +--------------+-------+----------+----------------------------+
    | test.csvtest | check | warning  | Table is marked as crashed |
    | test.csvtest | check | status   | OK                         |
    +--------------+-------+----------+----------------------------+
    2 rows in set (0.08 sec)
    

    Для ремонта таблицы Вы можете использовать REPAIR, это скопирует так много допустимых строк из существующих CSV данных, сколько возможно, а затем заменяет существующий CSV файл на восстановленные строки. Любые строки вне разрушенных данных будут потеряны.

    mysql> repair table csvtest;
    +--------------+--------+----------+----------+
    | Table        | Op     | Msg_type | Msg_text |
    +--------------+--------+----------+----------+
    | test.csvtest | repair | status   | OK       |
    +--------------+--------+----------+----------+
    1 row in set (0.02 sec)
    

    Предупреждение

    Обратите внимание, что в течение ремонта только строки из CSV файла до первой поврежденной строки скопированы к новой таблице. Все другие строки, даже допустимые строки, до первой поврежденной строки удалены!

    2.8.2. Ограничения CSV

    Важно: тип памяти CSV не поддерживает индексацию.

    Выделение разделов не обеспечивается для таблиц, использующих CSV. Начиная с MySQL 5.1.12, больше не возможно создать разбитую на разделы таблицу CSV (Глюк #19307).

    2.9. Тип памяти BLACKHOLE

    Тип памяти BLACKHOLE действует как черная дыра. Это принимает данные, но не сохраняет их. Поиски всегда возвращают пустой результат:

    mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = BLACKHOLE;
    Query OK, 0 rows affected (0.03 sec)
    mysql> INSERT INTO test VALUES(1,'record one'), (2,'record two');
    Query OK, 2 rows affected (0.00 sec)
    Records: 2 Duplicates: 0 Warnings: 0
    mysql> SELECT * FROM test;
    Empty set (0.00 sec)
    

    Тип памяти BLACKHOLE включен в двоичные дистрибутивы MySQL-Max. Чтобы его включить, если Вы формируете MySQL из исходного текста, вызовите configure с опцией --with-blackhole-storage-engine. Чтобы исследовать исходник типа памяти BLACKHOLE, смотрите каталог sql исходных текстов MySQL.

    Когда Вы создаете таблицу BLACKHOLE, сервер создает файл формата таблицы в каталоге баз данных. Имя файла начинается с имени таблицы и имеет расширение .frm. Не имеется никаких других файлов, связанных с таблицей.

    Тип памяти BLACKHOLE поддерживает все виды индексов. То есть, Вы можете включать индексные объявления в определении таблицы. Вы можете проверять наличие поддержки типа памяти BLACKHOLE этой инструкцией:

    mysql> SHOW VARIABLES LIKE 'have_blackhole_engine';
    

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

    Главный пишет в свой двоичный файл регистрации. Макет mysqld обрабатывает действия как подчиненный, применяя желательную комбинацию правил replicate-do-* и replicate-ignore-* после чего пишет новый, собственный, отфильтрованный двоичный файл регистрации. Этот фильтрованный файл регистрации передается подчиненному.

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

    Другие возможные использования типа памяти BLACKHOLE:

    • Проверка синтаксиса файла дампа.

    • Измерение непроизводительных затрат из двоичной регистрации, сравнивая эффективность, используя BLACKHOLE с и без двоичной регистрации.

    • BLACKHOLE по существу тип памяти пустой команды, так что это могло бы использоваться для нахождения критических параметров эффективности, не связанных с типом памяти непосредственно.

    Начиная с MySQL 5.1.4, тип памяти BLACKHOLE знает транзакции в том смысле, что совершенные транзакции записаны в двоичный файл регистрации, а отмененные транзакции уже нет.

    2.10 MySQL 5 FAQ по таблицам и типам памяти

    Questions and Answers

    2.10.1: Имеются ли любые новые типы памяти в MySQL 5.1?

    MySQL 5.1 представляет alpha-версию нового типа памяти Falcon.

    Также имелись значительные усовершенствования существующих типов памяти, в частности для NDB, который формирует основание MySQL Cluster.

    2.10.2: А какие-то типы памяти были удалены в MySQL 5.1?

    Да. MySQL 5.1 больше не поддерживает BDB. Любые существующие таблицы BDB должны быть преобразованы в другой тип перед обновлением до MySQL 5.1.

    2.10.3: Каковы уникальные выгоды типа памяти ARCHIVE?

    Тип памяти ARCHIVE идеально подходит для сохранения больших количеств данных без индексов, это имеет очень маленький размер и выполняет поиск данных с помощью сканирования таблицы.

    2.10.4: Какие новые свойства в MySQL 5.1 относятся ко всем типам памяти?

    Общие новые свойства типа views, сохраненных процедур, триггеров, INFORMATION_SCHEMA, точной математики (тип столбца DECIMAL), а также тип столбца BIT относятся ко всем типам памяти. Имеются также добавления и изменения для специфических типов.

    2.10.5: Какие изменения в поддерживаемые типы таблиц внесены в MySQL 5.1?

    Поддержка изменилась следующим образом:

    • Поддержка для таблиц ISAM была удалена в MySQL 5.0, и Вы должны теперь использовать таблицы MyISAM вместо ISAM. Чтобы преобразовать таблицу tblname из типа ISAM в MyISAM, просто выдайте инструкцию типа этой:

      ALTER TABLE tblname ENGINE=MYISAM;
      
    • Внутренний RAID для таблиц MyISAM был также удален в MySQL 5.0. Это прежде использовалось, чтобы позволить большие таблицы в файловых системах, которые не поддерживали размеры файла больше, чем 2 GB. Все современные файловые системы учитывают большие таблицы, кроме того, теперь имеются другие решения типа таблиц MERGE и views.

    • Тип столбца VARCHAR теперь сохраняет конечные пробелы во всех типах памяти.

    • Таблицы MEMORY (прежде известные как таблицы HEAP) также могут содержать столбцы VARCHAR.

    REPAIR, чтобы проверить и, если возможно, отремонтировать поврежденную таблицу CSV.

    При выполнении команды CHECK файл CSV будет проверен на правильность, ища правильные разделители полей, экранированные поля (соответствующие кавычками и/или ихmysqlpro/triggers.htm 600 0 0 63264 10643273310 10275 Глава 6. Триггеры

    Глава 6. Триггеры

    Поддержка для триггеров включена, начиная с MySQL 5.0.2. Триггер представляет собой именованный объект базы данных, который связан с таблицей, и он будет активизирован, когда специфическое событие происходит для таблицы. Например, следующие инструкции создают таблицу и вызывают триггер INSERT. Он суммирует значения, вставленные в один из столбцов таблицы:

    mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
        -> FOR EACH ROW SET @sum = @sum + NEW.amount;
    Query OK, 0 rows affected (0.06 sec)
    

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

    6.1. Синтаксис CREATE TRIGGER

    CREATE
      [DEFINER = {user | CURRENT_USER}]
      TRIGGER trigger_name trigger_time trigger_event
      ON tbl_name FOR EACH ROW trigger_stmt
    

    Эта инструкция создает новый триггер. CREATE TRIGGER была добавлена в MySQL 5.0.2. В настоящее время использование требует привилегии SUPER.

    Триггер становится связанным с таблицей с именем tbl_name, которое должно обратиться к постоянной таблице. Вы не можете связывать триггер с view или таблицей TEMPORARY.

    Когда триггер активизирован, предложение DEFINER определяет привилегии, которые применяются, как описано ниже в этом разделе.

    trigger_time задает время действия. Это может быть BEFORE или AFTER, чтобы задать, что триггер активизируется прежде или после инструкции, которая активизировала это.

    trigger_event указывает вид инструкции, которая активизирует триггер. Здесь trigger_event может быть одним из следующего:

    • INSERT: всякий раз, когда новая строка вставлена в таблицу. Например, через команды INSERT, LOAD DATA или REPLACE.

    • UPDATE: всякий раз, когда строка изменяется. Например, через инструкцию UPDATE.

    • DELETE: всякий раз, когда строка удалена из таблицы. Например, через инструкции DELETE и REPLACE. Однако, инструкции DROP TABLE и TRUNCATE относительно таблицы НЕ активизируют триггер, потому что они не используют DELETE!

    Важно понять, что trigger_event не представляет литеральный тип инструкции SQL, которая активизирует триггер, поскольку это представляет тип операции таблицы. Например, триггер INSERT активизирован не только инструкцией INSERT, но и LOAD DATA, потому что обе инструкции вставляют строки в таблицу.

    Не может быть двух триггеров для данной таблицы, которые имеют те же самые время действия и событие. Например, Вы не можете иметь два триггера BEFORE UPDATE для таблицы. Но Вы можете иметь BEFORE UPDATE и BEFORE INSERT или BEFORE UPDATE и AFTER UPDATE.

    trigger_stmt задает инструкцию, которая будет выполнена, когда триггер активизируется. Если Вы хотите выполнять много инструкций, используйте операторную конструкцию BEGIN ... END. Это также дает возможность Вам использовать те же самые инструкции, которые являются допустимыми внутри сохраненных подпрограмм.

    Замечание: в настоящее время триггеры не активизированы каскадными действиями внешнего ключа. Это ограничение будет сниматься как можно скорее.

    Обратите внимание: до MySQL 5.0.10 триггер не может содержать прямые ссылки к именам таблиц. С MySQL 5.0.10, Вы можете записывать имена, как показано в этом примере:

    CREATE TABLE test1(a1 INT);
    CREATE TABLE test2(a2 INT);
    CREATE TABLE test3(a3 INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
    CREATE TABLE test4(a4 INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
                       b4 INT DEFAULT 0);
    DELIMITER |
    CREATE TRIGGER testref BEFORE INSERT ON test1
      FOR EACH ROW BEGIN
        INSERT INTO test2 SET a2 = NEW.a1;
        DELETE FROM test3 WHERE a3 = NEW.a1;
        UPDATE test4 SET b4 = b4 + 1 WHERE a4 = NEW.a1;
      END;
    |
    DELIMITER ;
    INSERT INTO test3 (a3) VALUES
      (NULL), (NULL), (NULL), (NULL), (NULL),
      (NULL), (NULL), (NULL), (NULL), (NULL);
    INSERT INTO test4 (a4) VALUES
      (0), (0), (0), (0), (0), (0), (0), (0), (0), (0);
    

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

    mysql> INSERT INTO test1 VALUES 
        -> (1), (3), (1), (7), (1), (8), (4), (4);
    Query OK, 8 rows affected (0.01 sec)
    Records: 8  Duplicates: 0  Warnings: 0
    

    В результате данные в четырех таблицах будут следующие:

    mysql> SELECT * FROM test1;
    +------+
    | a1   |
    +------+
    |    1 |
    |    3 |
    |    1 |
    |    7 |
    |    1 |
    |    8 |
    |    4 |
    |    4 |
    +------+
    8 rows in set (0.00 sec)
    
    mysql> SELECT * FROM test2;
    +------+
    | a2   |
    +------+
    |    1 |
    |    3 |
    |    1 |
    |    7 |
    |    1 |
    |    8 |
    |    4 |
    |    4 |
    +------+
    8 rows in set (0.00 sec)
    
    mysql> SELECT * FROM test3;
    +----+
    | a3 |
    +----+
    |  2 |
    |  5 |
    |  6 |
    |  9 |
    | 10 |
    +----+
    5 rows in set (0.00 sec)
    
    mysql> SELECT * FROM test4;
    +----+------+
    | a4 | b4   |
    +----+------+
    |  1 |    3 |
    |  2 |    0 |
    |  3 |    1 |
    |  4 |    2 |
    |  5 |    0 |
    |  6 |    0 |
    |  7 |    1 |
    |  8 |    1 |
    |  9 |    0 |
    | 10 |    0 |
    +----+------+
    10 rows in set (0.00 sec)
    

    Вы можете обратиться к столбцам в подчиненной таблице (таблице, связанной с вызывающей), используя псевдонимы OLD и NEW. OLD.col_name обращается к столбцу существующей строки прежде, чем она модифицируется или удалится. NEW.col_name обращается к столбцу новой строки, которая будет вставлена, или же к существующей строке после того, как она модифицируется.

    Предложение DEFINER определяет логин MySQL, который нужно использовать при проверке привилегий доступа в вызове триггера. Это было добавлено в MySQL 5.0.17. Если дано значение user, это должно быть логином MySQL в формате 'user_name'@'host_name' (как в команде GRANT). Требуются переменные user_name и host_name. CURRENT_USER также может быть дан как CURRENT_USER(). Заданное по умолчанию значение DEFINER: пользователь, который выполняет инструкцию CREATE TRIGGER. Это также, как DEFINER = CURRENT_USER.

    Если Вы определяете предложение DEFINER, Вы не можете устанавливать значение к любому логину, кроме Вашего собственного, если Вы не имеете привилегию SUPER. Эти правила определяют допустимые значения пользователя в DEFINER:

    • Если Вы не имеете привилегии SUPER, единственное допустимое значение user: Ваш собственный логин, определенный буквально или используя CURRENT_USER. Вы не можете устанавливать DEFINER к некоторому другому логину.

    • Если Вы имеете привилегию SUPER, Вы можете определять любое синтаксически допустимое имя пользователя. Если такого логина фактически не существует, будет сгенерировано предупреждение.

      Хотя возможно создать триггер с несуществующим значением DEFINER, делать этого не следует, поскольку триггер не будет активизирован, пока DEFINER фактически не существует. Иначе, поведение относительно проверки привилегии неопределенно.

    Обратите внимание: так как MySQL в настоящее время требует, чтобы была привилегия SUPER для использования CREATE TRIGGER, только второе из предшествующих правил применяется. MySQL 5.1.6 вводит право TRIGGER и требует, чтобы эта привилегия наличествовала для создания триггера, так что с этой версии оба правила работают, а SUPER требуется только для определения значения DEFINER другого, чем Ваш собственный логин.

    Начиная с MySQL 5.0.17, MySQL проверяет привилегии триггера подобно этому:

    • В момент вызова CREATE TRIGGER пользователь, который выдает инструкцию, должен иметь привилегию SUPER.

    • При срабатывании триггера привилегии проверены на соответствие DEFINER. Пользователь должен иметь эти привилегии:

      • SUPER.

      • SELECT для подчиненной таблицы, если ссылки к столбцам таблицы происходят через OLD.col_name или or NEW.col_name в определении триггера.

      • UPDATE для подчиненной таблицы, если столбцы таблицы являются адресатами SET NEW.col_name = value, назначенными в определении триггера.

      • Любые другие привилегии обычно требуются для инструкций, выполненных триггером.

    До MySQL 5.0.17, MySQL проверяет привилегии подобно этому:

    • При вызове CREATE TRIGGER пользователь, который выдает инструкцию, должен иметь привилегию SUPER.

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

    Обратите внимание, что введение предложения DEFINER меняет значение CURRENT_USER() в определении триггера: функция CURRENT_USER() работает со значением DEFINER в MySQL 5.0.17 (и выше) или с тем пользователем, чьи действия заставили выполниться триггер (до MySQL 5.0.17).

    6.2. Синтаксис DROP TRIGGER

    DROP TRIGGER [schema_name.]trigger_name
    

    Это уничтожает триггер. Имя базы данных опционально. Если оно не задано, триггер удаляется из заданной по умолчанию базы данных, Вызов DROP TRIGGER был добавлен в MySQL 5.0.2. Использование требует привилегии SUPER.

    Обратите внимание: До MySQL 5.0.10, имя таблицы требовалось вместо имени схемы (table_name.trigger_name ). При обновлении с MySQL 5.0 до MySQL 5.0.10 или выше, Вы должны удалить все триггеры перед обновлением и вновь создать их впоследствии, иначе вызов DROP TRIGGER не работает после обновления.

    Кроме того, триггеры, созданные в MySQL 5.0.16 или выше, не могут быть удалены в MySQL 5.0.15 или ниже. Если Вы желаете выполнить такой возврат, Вы также должны в этом случае удалить все триггеры и заново их пересоздать после смены версий.

    6.3. Использование триггеров

    Поддержка триггеров включена, начиная с MySQL 5.0.2. Этот раздел обсуждает, как использовать триггеры и некоторые их ограничений.

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

    Триггер связан с таблицей и определен, чтобы активизироваться, когда для таблицы выполняется инструкция INSERT, DELETE или UPDATE. Триггер может быть установлен, чтобы активизироваться прежде или после вызова инструкции. Например, Вы можете иметь триггер, срабатывающий перед удалением каждой строки из таблицы, или после каждой модификации уже существующей строки в таблице.

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

    Следующие инструкции создают таблицу и триггер для нее:

    mysql> CREATE TABLE account (acct_num INT, amount DECIMAL(10,2));
    mysql> CREATE TRIGGER ins_sum BEFORE INSERT ON account
        ->        FOR EACH ROW SET @sum = @sum + NEW.amount;
    

    Команда CREATE TRIGGER создает триггер ins_sum, который связан с таблицей account. Это также включает предложения, которые определяют время активации, событие вызова, и что делать с активированным триггером дальше:

    • Ключевое слово BEFORE указывает время срабатывания. В этом случае триггер должен активизировать перед каждой строкой, вставленной в таблицу. Другое допустимое ключевое слово здесь: AFTER.

    • Ключевое слово INSERT указывает событие, которое активизирует триггер. В этом примере триггер срабатывает от инструкции INSERT. Вы можете также создавать триггеры для инструкций DELETE и UPDATE.

    • Инструкция FOR EACH ROW определяет, что триггер должен сработать один раз для каждой строки, на которую воздействует инструкция в примере. Собственно триггер представляет собой в данном случае простой SET, который накапливает значения, вставленные в столбец amount. Инструкция обращается к столбцу как NEW.amount, что означает "значение столбца amount, которое будет вставлено в новую строку".

    Чтобы использовать триггер, установите переменную сумматора в ноль, выполните инструкцию INSERT, а затем посмотрите то, какое значение переменная имеет позже:

    mysql> SET @sum = 0;
    mysql> INSERT INTO account VALUES(137,14.98),(141,1937.50),(97,-100.00);
    mysql> SELECT @sum AS 'Total amount inserted';
    +-----------------------+
    | Total amount inserted |
    +-----------------------+
    | 1852.48               |
    +-----------------------+
    

    В этом случае значение @sum после выполнения команды INSERT равно 14.98 + 1937.50 - 100 или 1852.48.

    Для уничтожения триггера выполните DROP TRIGGER. Вы должны определить имя схемы, если триггер не в заданной по умолчанию схеме:

    mysql> DROP TRIGGER test.ins_sum;
    

    Имена триггеров существуют в пространстве имен схемы. Это означает, что все триггеры должны иметь уникальные имена внутри схемы. Триггеры в различных схемах могут иметь то же самое имя.

    В дополнение к требованию, чтобы имя триггера было уникальным для схемы, имеются другие ограничения на типы триггеров, которые можно создавать. Вы не можете иметь два триггера для таблицы, которые имеют то же самое событие и время активации. Например, Вы не можете определять два триггера типа BEFORE INSERT или AFTER UPDATE для таблицы. Это редко должно быть значительным ограничением, поскольку запросто можно определить триггер, выполняющий много инструкций с помощью конструкции BEGIN ... END после FOR EACH ROW.

    Ключевые слова OLD и NEW дают возможность Вам обратиться к столбцам в строках, на которые воздействует триггер OLD и NEW не чувствительны к регистру. В триггере INSERT может использоваться только NEW.col_name : не имеется никакой старой строки. В триггере DELETE не ожидается никакой новой строки, так что может использоваться исключительно OLD.col_name. В триггере UPDATE Вы можете использовать OLD.col_name, чтобы обратиться к столбцам строки прежде, чем они изменятся, и NEW.col_name , чтобы обратиться к ним уже после внесения изменений.

    Столбец, именованный OLD только для чтения. Вы можете обратиться к этому столбцу (если Вы имеете привилегию SELECT, но не изменяете его. Столбец, именованный NEW может упоминаться, если Вы имеете привилегию SELECT для него. В триггере BEFORE Вы можете также изменять значение с SET NEW.col_name = value, если Вы имеете привилегию UPDATE для этого. Это означает, что Вы можете использовать триггер, чтобы изменить значения, которые будут вставлены в новую строку, или использовать это, чтобы модифицировать строку.

    В триггере BEFORE значение NEW для столбца AUTO_INCREMENT: 0, а не автоматически сгенерированный порядковый номер, который будет сгенерирован, когда новая запись фактически вставлена.

    OLD и NEW представляют собой MySQL-расширения триггеров.

    Используя конструкцию BEGIN ... END, Вы можете определять триггер, который выполняет много инструкций. Внутри блока BEGIN Вы также можете использовать другой синтаксис, который позволяется внутри сохраненных подпрограмм, типа условных выражений и циклов. Однако, точно как для сохраненных подпрограмм, если Вы используете программу mysql, чтобы определить триггер, необходимо переопределить операторный разделитель mysql так, чтобы Вы могли использовать ; как операторный разделитель внутри описания триггера. Следующий пример иллюстрирует эти моменты. Это определяет триггер UPDATE, который проверяет новое значение, которое нужно использовать для модифицирования каждой строки, и изменяет значение, чтобы оставаться внутри диапазона от 0 до 100. Это должно быть триггером типа BEFORE, потому что значение должно быть проверено прежде, чем оно используется, чтобы модифицировать строку:

    mysql> delimiter //
    mysql> CREATE TRIGGER upd_check BEFORE UPDATE ON account
        ->        FOR EACH ROW
        -> BEGIN
        ->   IF NEW.amount < 0 THEN SET NEW.amount = 0;
        ->      ELSEIF NEW.amount > 100 THEN SET NEW.amount = 100;
        ->   END IF;
        -> END;//
    mysql> delimiter ;
    

    Может быть проще определить сохраненную процедуру отдельно и затем вызвать ее из триггера простой инструкцией CALL. Это также выгодно, если Вы хотите вызывать ту же самую подпрограмму изнутри нескольких триггеров.

    Имеются некоторые ограничения на то, что может появляться в инструкциях:

    • Триггер не может использовать инструкцию CALL, чтобы вызвать сохраненные процедуры, которые возвращают данные пользователю или применяют динамический SQL. Процедурам позволяется возвратить данные триггеру через параметры OUT или INOUT.

    • Триггер не может использовать инструкции, которые явно или неявно начинают или заканчивают транзакцию, типа START TRANSACTION, COMMIT или ROLLBACK.

    • До MySQL 5.0.10 триггер не может содержать прямые ссылки к именам таблиц.

    MySQL обрабатывает ошибки в выполнении триггеров следующим образом:

    • Если проблемы с триггером BEFORE, операции на соответствующей строке просто не выполняются.

    • Триггер BEFORE активизирован попыткой вставить или изменить строку, независимо от того, удачной ли была попытка.

    • Триггер AFTER выполнен только, если триггер BEFORE и операция со строкой (вместе!) выполняются успешно.

    • Ошибка в триггере BEFORE или AFTER вызывает сбой всей инструкции, которая вызвала триггер.

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

    6.4. MySQL 5 FAQ по триггерам

    6.4.1: Имеется ли форум для обсуждения триггеров в MySQL?

    Да. http://forums.mysql.com/list.php?99.

    6.4.2: MySQL 5.1 имеет триггеры операторного уровня или уровня строки?

    В MySQL 5.1 все триггеры FOR EACH ROW, то есть триггер активизирован для каждой строки, которая вставлена, модифицируется или удалена. MySQL 5.1 не поддерживает использование триггеров FOR EACH STATEMENT.

    6.4.3: Имеется ли любое значение по умолчанию для триггеров?

    Неявно. MySQL имеет специфическое специальное поведение для некоторых столбцов TIMESTAMP, а также для столбцов, которые определены, используя AUTO_INCREMENT.

    6.4.4: Как управлять триггерами в MySQL?

    В MySQL 5.1 триггер может быть создан, используя инструкцию CREATE TRIGGER, а удален инструкцией DROP TRIGGER.

    Информация относительно триггеров может быть получена, запрашивая таблицу INFORMATION_SCHEMA.TRIGGERS.

    6.4.5: Имеется ли способ просмотреть все триггеры в конкретной базе данных?

    Да. Вы можете получать распечатку всех триггеров, определенных в базе данных dbname, запросом к таблице INFORMATION_SCHEMA.TRIGGERS примерно так:

    SELECT TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE,
           ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS
           WHERE TRIGGER_SCHEMA='dbname';
    

    Вы можете также использовать инструкцию SHOW TRIGGERS, которая является специфической для MySQL.

    6.4.6: Где хранятся триггеры?

    Триггеры в настоящее время сохранены в .TRG-файлах, один такой файл на таблицу. Другими словами, триггер принадлежит таблице.

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

    6.4.7: Может триггер вызывать сохраненную процедуру?

    Да.

    6.4.8: Может триггер обращаться к таблицам?

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

    6.4.9: Может триггер вызывать внешнюю прикладную программу через UDF?

    Нет, не в настоящее время.

    6.4.10: Может триггер модифицировать таблицы на удаленном сервере?

    Да. Таблица на удаленном сервере могла бы модифицироваться, используя тип памяти FEDERATED.

    гера выполните DROP TRIGGER. Вы должны определить имя схемы, если триггер не в заданной по умолчанию схеме:

    mysql> DROP TRIGGER test.ins_sum;
    

    Имена триггеров существуют в пространстве имен схемы. Это означает, что все триггеры должны иметь уникальные имена вmysqlpro/views.htm 600 0 0 65225 10643273332 7607 Глава 7. Views

    Глава 7. Views

    Views (включая обновляемые views) выполнены в MySQL Server 5.0. Views доступны в двоичных выпусках 5.0.1 и выше.

    Эта глава обсуждает следующие темы:

    • Создание или изменение views через CREATE VIEW или ALTER VIEW

    • Удаление views командой DROP VIEW

    Обсуждение ограничений на использование views дано в разделе " 11.4. Ограничения на Views".

    Чтобы использовать views, если выполнен апгрейд до MySQL 5.0.1, Вы должны обновить таблицы предоставления привилегий, чтобы они содержали привилегии, связанные с view.

    Метаданные относительно views могут быть получены из таблицы INFORMATION_SCHEMA.VIEWS или используя инструкцию SHOW CREATE VIEW.

    7.1. Синтаксис ALTER VIEW

    ALTER [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
          [DEFINER = {user | CURRENT_USER}]
          [SQL SECURITY {DEFINER | INVOKER}]
          VIEW view_name [(column_list)]
          AS select_statement
          [WITH [CASCADED | LOCAL] CHECK OPTION]
    

    Эта инструкция изменяет определение существующего view. Синтаксис для CREATE VIEW подобен этому. Эта инструкция требует привилегий CREATE VIEW и DROP для этого view, а также некоторой привилегии для каждого столбца, упоминаемого в инструкции SELECT.

    Эта инструкция была добавлена в MySQL 5.0.1. Предложения DEFINER и SQL SECURITY могут использоваться с MySQL 5.0.16, чтобы определить контекст защиты, который нужно использовать при проверке привилегий доступа при вызове view. Подробности изложены в разделе "7.2. Синтаксис CREATE VIEW ".

    7.2. Синтаксис CREATE VIEW

    CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
      [DEFINER = {user | CURRENT_USER}]
      [SQL SECURITY {DEFINER | INVOKER}]
      VIEW view_name [(column_list)]
      AS select_statement
      [WITH [CASCADED | LOCAL] CHECK OPTION]
    

    Эта инструкция создает новый view или заменяет существующий, если дано предложение OR REPLACE. Инструкция SELECT select_statement обеспечивает определение view. Инструкция может выбирать из основных таблиц или других views.

    Эта инструкция требует привилегии CREATE VIEW для view и некоторой привилегии для каждого столбца, выбранного инструкцией SELECT. Для столбцов, используемых в другом месте в инструкции SELECT, Вы должны иметь привилегию SELECT. Если присутствует предложение OR REPLACE, Вы должны также иметь привилегию DROP для view.

    Каждый view принадлежит базе данных. По умолчанию, новый view создан в заданной по умолчанию базе данных. Чтобы явно создавать view в указанной базе данных, определите его имя как db_name.view_name.

    mysql> CREATE VIEW test.v AS SELECT * FROM t;
    

    Основные таблицы и views совместно используют то же самое пространство имен внутри базы данных, так что база данных не может содержать основную таблицу и view, которые имеют то же самое имя.

    Views должны иметь уникальные имена столбца без дубликатов, точно так же, как основные таблицы. По умолчанию, имена столбцов, найденных инструкцией SELECT используются для имени столбца view. Чтобы определять явные имена для столбцов view, может быть задано факультативное предложение column_list как список разделяемых запятой идентификаторов. Число имен в column_list должно быть таким же, как число столбцов, найденных командой SELECT.

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

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

    view может быть создан из многих видов инструкций SELECT. Он может обратиться к основным таблицам или другим view. Это может использовать объединения, UNION и подзапросы. SELECT не обязан обращаться к каким-либо таблицам. Следующий пример определяет view, который выбирает два столбца из другой таблицы, также как выражение, вычисленное из данных этих столбцов:

    mysql> CREATE TABLE t (qty INT, price INT);
    mysql> INSERT INTO t VALUES(3, 50);
    mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
    mysql> SELECT * FROM v;
    +------+-------+-------+
    | qty  | price | value |
    +------+-------+-------+
    |    3 |    50 |   150 |
    +------+-------+-------+
    

    Определение view подчиненно следующим ограничениям:

    • Инструкция SELECT не может содержать подзапрос в предложении FROM.

    • Инструкция SELECT не может обратиться к переменным пользователя или системы.

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

    • Внутри сохраненной подпрограммы, определение не может обратиться к стандартным параметрам или локальным переменным.

    • Любая таблица или view, упоминаемый в определении, должны существовать. Однако, после того, как view был создан, можно удалить таблицу или view, к которому определение обращается. В этом случае, использование view приводит к ошибке. Чтобы проверить определение view для выявления проблем этого вида, используйте инструкцию CHECK TABLE.

    • Определение не может обратиться к таблице типа TEMPORARY, и Вы не можете создавать TEMPORARY view.

    • Таблицы, поименованные в определении view, должны уже существовать.

    • Вы не можете связывать триггер с view.

    ORDER BY позволяется в определении view, но это игнорируется, если Вы выбираете из view, используя инструкцию, которая имеет собственный ORDER BY.

    Для других параметров или предложений в определении, которые добавлены к параметрам или предложениям инструкции, которая ссылается на view, эффект не определен. Например, если определение view включает предложение LIMIT, и Вы выбираете из view, применяя инструкцию, которая имеет собственное предложение LIMIT, не определено, которое ограничение применяется. Тот же самый принцип применяется к параметрам типа ALL, DISTINCT или SQL_SMALL_RESULT, которые следуют за ключевым словом SELECT, к предложениям типа INTO, FOR UPDATE, LOCK IN SHARE MODE и PROCEDURE.

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

    mysql> CREATE VIEW v AS SELECT CHARSET(CHAR(65)), COLLATION(CHAR(65));
    Query OK, 0 rows affected (0.00 sec)
    mysql> SET NAMES 'latin1';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM v;
    +-------------------+---------------------+
    | CHARSET(CHAR(65)) | COLLATION(CHAR(65)) |
    +-------------------+---------------------+
    | latin1            | latin1_swedish_ci   |
    +-------------------+---------------------+
    1 row in set (0.00 sec)
    
    mysql> SET NAMES 'utf8';
    Query OK, 0 rows affected (0.00 sec)
    mysql> SELECT * FROM v;
    +-------------------+---------------------+
    | CHARSET(CHAR(65)) | COLLATION(CHAR(65)) |
    +-------------------+---------------------+
    | utf8              | utf8_general_ci     |
    +-------------------+---------------------+
    1 row in set (0.00 sec)
    

    Предложения DEFINER и SQL SECURITY определяют контекст защиты, который нужно использовать при проверке привилегий доступа при вызове view. Они были добавлены в MySQL 5.0.13, но реально работают с MySQL 5.0.16.

    CURRENT_USER также известен как CURRENT_USER().

    Внутри сохраненной подпрограммы, которая определена с характеристикой SQL SECURITY DEFINER, CURRENT_USER возвращает создателя подпрограммы. Это также воздействует на view, определенный внутри такой подпрограммы, если определение view содержит значение DEFINER для CURRENT_USER.

    Заданное по умолчанию значение DEFINER: пользователь, который выполняет инструкцию CREATE VIEW (поскольку DEFINER = CURRENT_USER). Если задано значение user, это должно быть логином MySQL в формате 'user_name'@'host_name' (тот же самый формат, используется в инструкции GRANT). Требуются значения user_name и host_name.

    Если Вы определяете предложение DEFINER, Вы не можете устанавливать значение к любому пользователю, если не имеете привилегии SUPER. Эти правила определяют допустимые значения пользователя для предложения DEFINER:

    • Если Вы не имеете привилегии SUPER, единственное допустимое значение user: Ваш собственный логин, определенный буквально или используя CURRENT_USER. Вы не можете устанавливать DEFINER к некоторому другому логину.

    • Если Вы имеете привилегию SUPER, Вы можете определять любой синтаксически допустимый логин. Если он фактически не существует, будет сгенерировано предупреждение.

    Характеристика SQL SECURITY определяет, который логин MySQL использовать при проверке привилегий доступа для view. Допустимые значения: DEFINER и INVOKER. Они указывают, что view должен быть выполним пользователем, который определил или вызвал его, соответственно. Заданное по умолчанию значение для SQL SECURITY: DEFINER.

    Начиная с MySQL 5.0.16 (когда были введены в строй DEFINER и SQL SECURITY), привилегии view проверяются следующим образом:

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

    • Во время выполнения view, привилегии для объектов, к которым обращается view, проверены относительно привилегий создателя или исполнителя view, в зависимости от того, является ли характеристика SQL SECURITY равной DEFINER или INVOKER.

    • Если выполнение view вызывает выполнение сохраненной функции, инструкции прверки привилегии, выполненные внутри функции, зависят от того, определена ли функция с характеристикой SQL SECURITY, равной DEFINER или INVOKER. Если характеристика защиты DEFINER, функция выполняется с привилегиями создателя. Если характеристика INVOKER, функция выполняется с привилегиями, определенными в соответствии с характеристикой SQL SECURITY для view.

    До MySQL 5.0.16 привилегии, требуемые для объектов, используемых в view, проверялись при создании view.

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

    CREATE VIEW v AS SELECT * FROM t WHERE t.id = f(t.name);
    

    Предположим, что f() содержит инструкцию типа этого:

    IF name IS NULL then CALL p1();
       ELSE CALL p2();
    END IF;
    

    Привилегии, требуемые для выполнения инструкций внутри f(), должны быть проверены, когда f() выполняется. Это могло бы означать, что привилегии необходимы для p1() или p2(), в зависимости от пути выполнения внутри f(). Те привилегии должны быть проверены во время выполнения, а пользователь, который должен обладать привилегиями, определен значениями SQL SECURITY функции f() и view v.

    DEFINER и предложение SQL SECURITY для views представляют собой расширения к стандарту SQL. В обычном SQL views обработаны, используя правила для SQL SECURITY INVOKER.

    Если Вы вызываете view, который был создан до MySQL 5.0.13, это обрабатывается, как если бы это было создано с предложением SQL SECURITY DEFINER и со значением DEFINER, равным Вашему логину. Однако, потому что фактический definer неизвестен, MySQL выдает предупреждение. Чтобы обойти предупреждение, достаточно вновь создать view, так чтобы определение view включило предложение DEFINER.

    Факультативное предложение ALGORITHM задает расширение MySQL для стандартного SQL. ALGORITHM берет три значения: MERGE, TEMPTABLE или UNDEFINED. Заданный по умолчанию UNDEFINED, если никакое предложение ALGORITHM не присутствует. Алгоритм воздействует на то, как MySQL обрабатывает view.

    Для MERGE текст инструкции, которая обращается к view, и определение view объединены так, что части определения view заменяют соответствующие части инструкции.

    Для TEMPTABLE результаты из просмотра view помещаются во временную таблицу, которая затем используется, чтобы выполнить инструкцию.

    Для UNDEFINED MySQL выбирает, который алгоритм использовать. Это предпочитает MERGE варианту TEMPTABLE, если возможно, поскольку MERGE обычно более эффективен и потому, что view не может быть обновляемым, если временная таблица используется.

    Причина выбирать TEMPTABLE явно: блокировки на основных таблицах могут быть сняты после того, как временная таблица была создана, но прежде, чем это используется, чтобы закончить обрабатывать инструкцию. Это могло бы привести к более быстрому снятию блокировки, чем алгоритм MERGE так, чтобы другая клиентура, которая использует view, не была блокирована очень долго.

    Алгоритм view может быть UNDEFINED по трем причинам:

    • Никакое предложение ALGORITHM не присутствует в инструкции CREATE VIEW.

    • Инструкция CREATE VIEW имеет явное предложение ALGORITHM = UNDEFINED.

    • ALGORITHM = MERGE определен для view, который может быть обработан только с временной таблицей. В этом случае MySQL генерирует предупреждение и устанавливает алгоритм к UNDEFINED (не к TEMPTABLE!).

    Как упомянуто ранее, MERGE обработан, объединяя соответствующие части определения view в инструкцию, которая обращается к view. Следующие примеры кратко иллюстрируют, как работает алгоритм MERGE. Примеры принимают, что имеется view v_merge, который имеет это определение:

    CREATE ALGORITHM = MERGE VIEW v_merge (vc1, vc2) AS
           SELECT c1, c2 FROM t WHERE c3 > 100;
    

    Пример 1: Предположим, что мы выдаем эту инструкцию:

    SELECT * FROM v_merge;
    

    MySQL обрабатывает инструкцию следующим образом:

    • v_merge становится t.

    • * становится vc1, vc2, которые соответствуют c1, c2.

    • Предложение WHERE из view добавляется.

    Возникающая в результате инструкция, которая будет выполнена:

    SELECT c1, c2 FROM t WHERE c3 > 100;
    

    Пример 2: Предположим, что мы выдаем эту инструкцию:

    SELECT * FROM v_merge WHERE vc1 < 100;
    

    Эта инструкция обработана аналогично предыдущей за исключением того, что vc1 < 100 становится c1 <100 и предложение WHERE из view добавлено к предложению WHERE инструкции, используя связку AND (круглые скобки добавлены, чтобы удостовериться, что части предложения выполнены с правильным старшинством). Возникающая в результате инструкция, которая будет выполнена:

    SELECT c1, c2 FROM t WHERE (c3 > 100) AND (c1 < 100);
    

    Действительно, инструкция, которая будет выполнена, имеет предложение WHERE этой формы:

    WHERE (select WHERE) AND (view WHERE)
    

    Алгоритм MERGE требует взаимно однозначной связи между строками в view и строках в основной таблице. Если эта связь не действует, временная таблица должна использоваться вместо этого. Недостаток взаимно однозначной связи происходит, если view содержит любую из этих конструкций:

    • Агрегатные функции (SUM(), MIN(), MAX(), COUNT() и им подобные)

    • DISTINCT

    • GROUP BY

    • HAVING

    • UNION или UNION ALL

    • Обращается только к литеральным значениям (в этом случае не имеется никакой основной таблицы).

    Некоторые views обновляемые. То есть Вы можете использовать их в инструкциях типа UPDATE, DELETE или INSERT, чтобы модифицировать содержание основной таблицы. Чтобы view был обновляемым, должна иметься взаимно однозначная связь между строками в view и строками в основной таблице. Имеются также некоторые другие конструкции, которые делают view не обновляемым. А именно: view не обновляемый, если он содержит любое из следующего:

    • Агрегатные функции (SUM(), MIN(), MAX(), COUNT() и им подобные)

    • DISTINCT

    • GROUP BY

    • HAVING

    • UNION или UNION ALL

    • Подзапросы в списке select

    • Join

    • Необновляемые view в FROM

    • Подзапросы в WHERE, ссылающиеся на таблицы в FROM

    • Обращается только к литеральным значениям (в этом случае не имеется никакой основной таблицы, чтобы модифицировать)

    • ALGORITHM = TEMPTABLE (использование временной таблицы всегда делает view не обновляемым)

    Относительно вставляемости (обновляемости с инструкциями INSERT): обновляемый view является вставляемым, если он удовлетворяет этим дополнительным требованиям для столбцов view:

    • Не должно иметься никаких двойных имен столбца view.

    • view должен содержать все столбцы в основной таблице, которые не имеют значения по умолчанию.

    • Столбцы view должны быть простыми ссылками на столбец, но не полученными столбцами. Под полученными столбцами понимаются столбцы, которые получены из выражения. Вот примеры полученных столбцов:

      3.14159
      col1 + 3
      UPPER(col2)
      col3 / col4
      (подзапрос)
      

    view, который имеет смесь простых ссылок столбца и полученных столбцов, не вставляемый, но он может быть обновляемым, если Вы модифицируете только те столбцы, которые не получены. Рассмотрите этот view:

    CREATE VIEW v AS SELECT col1, 1 AS col2 FROM t;
    

    Этот view не вставляемый, потому что col2 получен из выражения. Но это обновляемый view, если модификация не пробует менять col2. Эта модификация допустима:

    UPDATE v SET col1 = 0;
    

    А вот эта модификация уже не допустима, потому что она пытается модифицировать полученный столбец:

    UPDATE v SET col2 = 0;
    

    Для мультитабличного view иногда есть возможность обновляться, если это обрабатывается через алгоритм MERGE. Для этого view должен использовать внутреннее объединение (не внешнее объединение или UNION). Также, только одиночная таблица в определении view может модифицироваться, так что предложение SET должно называть только столбцы одной из таблиц в view. Views, которые используют UNION ALL отвергнуты даже при том, что они могли бы быть теоретически обновляемыми, потому что реализация использует временные таблицы, чтобы обработать их.

    Для мультитабличного обновляемого view, INSERT может работать, если это вставляет в одиночную таблицу. DELETE не обеспечивается вообще.

    Предложение WITH CHECK OPTION может быть дано для обновляемого view, чтобы предотвратить вставки или модификации в строки за исключением тех, для которых предложение WHERE в select_statement истинно.

    В предложении WITH CHECK OPTION для обновляемого view ключевые слова LOCAL и CASCADED определяют контекст тестирования проверки, когда view определен в терминах другого view. Ключевое слово ограничивает LOCAL CHECK OPTION только определяемым view. CASCADED задает проверку для основных view, которые также будут оценены. Когда никакое ключевое слово не дано, значение по умолчанию: CASCADED. Рассмотрите определения для следующей таблицы и набора view:

    mysql> CREATE TABLE t1 (a INT);
    mysql> CREATE VIEW v1 AS SELECT * FROM t1 WHERE a < 2
        ->        WITH CHECK OPTION;
    mysql> CREATE VIEW v2 AS SELECT * FROM v1 WHERE a > 0
        ->        WITH LOCAL CHECK OPTION;
    mysql> CREATE VIEW v3 AS SELECT * FROM v1 WHERE a > 0
        ->        WITH CASCADED CHECK OPTION;
    

    Здесь view v2 и v3 определены в терминах другого view, а именно v1. v2 имеет опцию проверки LOCAL, так что вставки проверены только для v2. v3 имеет опцию проверки CASCADED, так что вставки проверены не только по собственной проверки, но и для таковых основных view. Следующие инструкции иллюстрируют эти различия:

    mysql> INSERT INTO v2 VALUES (2);
    Query OK, 1 row affected (0.00 sec)
    mysql> INSERT INTO v3 VALUES (2);
    ERROR 1369 (HY000): CHECK OPTION failed 'test.v3'
    

    На обновляемость view можно воздействовать значением переменной системы updatable_views_with_limit. Команда CREATE VIEW была добавлена в MySQL 5.0.1. WITH CHECK OPTION было выполнено в MySQL 5.0.2.

    7.3. Синтаксис DROP VIEW

    DROP VIEW [IF EXISTS]
         view_name [, view_name] ...
         [RESTRICT | CASCADE]
    

    DROP VIEW удаляет один или большее количество view. Вы должны иметь привилегию DROP для каждого view. Если любой из view, именованных в списке параметров не существует, MySQL возвращает индикацию ошибки с именем, которые не существует, но удаляет все view в списке, которые существуют.

    Предложение IF EXISTS предотвращает ошибку для просмотров, которые не существуют. Когда это предложение дано, NOTE будет сгенерировано для каждого несуществующего view.

    RESTRICT и CASCADE, если заданы, анализируются и игнорируются. Эта инструкция была добавлена в MySQL 5.0.1.

    7.4. MySQL 5.1 FAQ Views

    7.4.1: Имеется ли форум для обсуждения MySQL Views?

    Да. http://forums.mysql.com/list.php?100

    7.4.2: Что случается с view, если основная таблица удалена или переименована?

    После создания view, возможно удалить или изменить таблицу (или view), к которому обращается определение. Чтобы проверять определение view для выявления проблем этого вида, используйте инструкцию CHECK TABLE.

    7.4.3: MySQL 5.1 имеет кадры таблицы?

    Нет.

    7.4.4: MySQL 5.1 имеет осуществленные views?

    Нет.

    7.4.5: Можно ли вставлять во views, которые основаны на объединениях?

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

    SELECT c1, c2 FROM t WHERE c3 > 100;

    Пример 1: Предположим, что мы выдаем эту инструкцию:

    SELECT * FROM v_merge;
    

    MySQL обрабатывает инструкцию следующим образом:

    • v_merge становится t.

    • * становится vc1, vc2, которые elect WHERE) AND (view WHERE)

      Алгоритм MERGE требует взаимно однозначной связи между строками в view и строках в основной таблице. Если эта связь не действует, временная таблица должна использоваться вместо этого. Недостаток взаимно однозначной связи происходит, если view содержит любую из этих конструкций:

      • Агрегатные функции (SUM(), MIN(), MAX(), COUNT() и им подобные)

      • DISTINCT

      • GROUP BY

      • HAVING

      • UNION или UNION ALL

      • Обращается только к литеральным значениям (в этом случае не имеется никакой основной таблицы).

      Некоторые views обновляемые. То есть Вы можете использовать их в инструкциях типа UPDATE, DELETE или INSERT, чтобы модифицировать содержание основной таблицы. Чтобы view был обновляемым, должна иметься взаимно однозначная связь между строками в view и строками в основной таблице. Имеются также некоторые другие конструкции, которые делают view не обновляемым. А именно: view не обновляемый, если он содержит любое из следующего:

      • Агрегатные функции (SUM(), MIN(), MAX(), COUNT() и им подобные)

      • DISTINCT

      • GROUP BY

      • HAVING

      • UNION или UNION ALL

      • Подзапросы в списке select

      • Join

      • Необновляемые view в FROM

      • Подзапросы в WHERE, ссылающиеся на таблицы в FROM

      • Обращается только к литеральным значениям (в этом случае не имеется никакой основной таблицы, чтобы модифицировать)

      • ALGORITHM = TEMPTABLE (использование временной таблицы всегда делает view не обновляемым)

      Относительно вставляемости (обновляемости с инструкциями INSERT): обновляемый view является вставляемым, если он удовлетворяет этим дополнительным требованиям для столбцов view:

      • Не должно иметься никаких двойных имен столбца view.

      • view должен содержать все столбцы в основной таблице, которые не имеют значения по умолчанию.

      • Столбцы view должны быть простыми ссылками на столбец, но не полученными столбцами. Под полученными столбцами понимаются столбцы, которые получены из выражения. Вот примеры полученных столбцов:

        3.14159
        col1 + 3
        UPPER(col2)
        col3 / col4
        (подзапрос)
        

      view, который имеет смесь простых ссылок столбца и полученных столбцов, не вставляемый, но он может быть обновляемым, если Вы модифицируете только те столбцы, которые не получены. Рассмотрите этот view:

      CREATE VIEW v AS SELECT col1, 1 AS col2 FROM t;
      

      Этот view не вставляемый, потому что col2 получен из выражения. Но это обновляемый view, если модификация не пробует менять col2. Эта модификация допустима:

      UPDATE v SET col1 = 0;
      

      А вот эта модификация уже не допустима, потому что она пытается модифицировать полученный столбец:

      UPDATE v SET col2 = 0;
      

      Для мультитабличного view иногда есть возможность обновляться, если это обрабатывается через алгоритм MERGE. Для этого view должен использовать внутреннее объединение (не внешнее объединение или UNION). Также, только одиночная таблица в определении view может модифицироваться, так что предложение SET должно называть только столбцы одной из таблиц в view. Views, которые используют UNION ALL отвергнуты даже при том, что они могли бы быть теоретически обновляемыми, потому что реализация использует временные таблицы, чтобы обработать их.

      Для мультитабличного обновляемого view, INSERT может работать, если это вставляет в одиночную таблицу. DELETE не обеспечивается вообще.

      Предложение WITH CHECK OPTION может быть дано для обновляемого view, чтобы предотвратить вставки или модификации в строки за исключением тех, для которых предложение WHERE в select_statement истинно.

      В предложении WITH CHECK OPTION для обновляемого view ключевые слова LOCAL и CASCADED определяют контекст тестирования проверки, когда view определен в терминах другого view. Ключевое слово ограничивает LOCAL CHECK OPTION только определяемым view. CASCADED задает проверку для основных view, которые также будут оценены. Когда никакое ключевое слово не дано, значение по умолчанию: CASCADED. Рассмотрите определения для следующей таблицы и набора view:

      mysql> CREATE TABLE t1 (a INT);
      mysql> CREATE VIEW v1 AS SELECT * FROM t1 WHERE a < 2
          ->        WITH CHECK OPTION;
      mysql> CREATE VIEW v2 AS SELECT * FROM v1 WHERE a > 0
          ->        WITH LOCAL CHECK OPTION;
      mysql> CREATE VIEW v3 AS SELECT * FROM v1 WHERE a > 0
          ->        WITH CASCADED CHECK OPTION;
      

      Здесь view v2 и v3 определены в терминах другого view, а именно v1. v2 имеет опцию проверки LOCAL, так что вставки проверены только для v2. v3 имеет опцию проверки CASCADED, так что вставки проверены не только по собственной проверки, но и для таковых основных view. Следующие инструкции иллюстрируют эти различия:

      mysql> INSERT INTO v2 VALUES (2);
      Query OK, 1 row affected (0.00 sec)
      mysql> INSERT INTO v3 VALUES (2);
      ERROR 1369 (HY000): CHECK OPTION failed 'test.v3'
      

      На обновляемость view можно воздействовать значением переменной системы updatable_views_with_limit. Команда CREATE VIEW была добавлена в MySQL 5.0.1. WITH CHECK OPTION было выполнено в MySQL 5.0.2.

      7.3. Синтаксис DROP VIEW

      DROP VIEW [IF EXISTS]
           view_name [, view_name] ...
           [RESTRICT | CASCADE]
      

      DROP VIEW удаляет один или большее количество view. Вы должны иметь привилегию DROP для каждого view. Если любой из view, именованных в списке параметров не существует, MySQL возвращает индикацию ошибки с именем, которые не существует, но удаляет все view в списке, которые существуют.

      Предложение IF EXISTS предотвращает ошибку для просмотров, которые не существуют. Когда это предложение дано, NOTE будет сгенерировано для каждого несуществующего view.

      RESTRICT и CASCADE, если заданы, анализируются и игнорируются. Эта инструкция была добавлена в MySQL 5.0.1.

      7.4. MySQL 5.1 FAQ Views

      7.4.1: Имеется ли форум для обсуждения MySQL Views?

      Да. http://forums.mysql.com/list.php?100

      7.4.2: Что случается с view, если основная таблица удалена или переименована?

      После создания view, возможно удалить или изменить таблицу (или view), к которому обращается определение. Чтобы проверять определение view для выявления проблем этого вида, используйте инструкцию CHECK TABLE.

      7.4.3: MySQL 5.1 имеет кадры таблицы?

      Нет.

      7.4.4: MySQL 5.1 имеет осуществленные views?

      Нет.

      7.4.5: Можно ли вставлять во views, которые основаны на объединениях?

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

      SELECT c1, c2 FROM t WHERE c3 > 100;

      Пример 1: Предположим, что мы выдаем эту инструкцию:

      SELECT * FROM v_merge;
      

      MySQL обрабатывает инструкцию следующим образом:

      • v_merge становится t.

      • * становится vc1, vc2, которые elect WHERE) AND (view WHERE)

        Алгоритм MERGE требует взаимно однозначной связи между строками в view и строках в основной таблице. Если эта связь не действует, временная таблица должна использоваться вместо этого. Недостаток взаимно однозначной связи происходит, если view содержит любую из этих конструкций:

        • Агрегатные функции (SUM(), MIN(), MAX(), COUNT() и им подобные)

        • DISTINCT

        • GROUP BY

        • HAVING

        • UNION или UNION ALL

        • Обращается только к литеральным значениям (в этом случае не имеется никакой основной таблицы).

        Некоторые views обновляемые. То есть Вы можете использовать их в инструкциях типа UPDATE, DELETE или INSERT, чтобы модифицировать содержание основной таблицы. Чтобы view был обновляемым, должна иметься взаимно однозначная связь между строками в view и строками в основной таблице. Имеются также некоторые другие конструкции, которые делают view не обновляемым. А именно: view не обновляемый, если он содержит любое из следующего:

        • Агрегатные функции (SUM(), MIN(), MAX(), COUNT() и им подобные)

        • DISTINCT

        • GROUP BY

        • HAVING

        • UNION или UNION ALL

        • Подзапросы в списке select

        • Join

        • Необновляемые view в FROM

        • Подзапросы в WHERE, ссылающиеся на таблицы в FROM

        • Обращается только к литеральным значениям (в этом случае не имеется никакой основной таблицы, чтобы модифицировать)

        • ALGORITHM = TEMPTABLE (использование временной таблицы всегда делает view не обновляемым)

        Относительно вставляемости (обновляемости с инструкциями INSERT): обновляемый view является вставляемым, если он удовлетворяет этим дополнительным требованиям для столбцов view:

        • Не должно иметься никаких двойных имен столбца view.

        • view должен содержать все столбцы в основной таблице, которые не имеют значения по умолчанию.

        • Столбцы view должны быть простыми ссылками на столбец, но не полученными столбцами. Под полученными столбцами понимаются столбцы, которые получены из выражения. Вот примеры полученных столбцов:

          3.14159
          col1 + 3
          UPPER(col2)
          col3 / col4
          (подзапрос)
          

        view, который имеет смесь простых ссылок столбца и полученных столбцов, не вставляемый, но он может быть обновляемым, если Вы модифицируете только те столбцы, которые не получены. Рассмотрите этот view:

        CREATE VIEW v AS SELECT col1, 1 AS col2 FROM t;
        

        Этот view не вставляемый, потому что col2 получен из выражения. Но это обновляемый view, если модификация не пробует менять col2. Эта модификация допустима:

        UPDATE v SET col1 = 0;
        

        А вот эта модификация уже не допустима, потому что она пытается модифицировать полученный столбец:

        UPDATE v SET col2 = 0;
        

        Для мультитабличного view иногда есть возможность обновляться, если это обрабатывается через алгоритм MERGE. Для этого view должен использовать внутреннее объединение (не внешнее объединение или UNION). Также, только одиночная таблица в определении view может модифицироваться, так что предложение SET должно называть только столбцы одной из таблиц в view. Views, которые используют UNION ALL отвергнуты даже при том, что они могли бы быть теоретически обновляемыми, потому что реализация использует временные таблицы, чтобы обработать их.

        Для мультитабличного обновляемого view, INSERT может работать, если это вставляет в одиночную таблицу. DELETE не обеспечивается вообще.

        Предложение WITH CHECK OPTION может быть дано для обновляемого view, чтобы предотвратить вставки или модификации в строки за исключением тех, для которых предложение WHERE в select_statement истинно.

        В предложении WITH CHECK OPTION для обновляемого view ключевые слова LOCAL и CASCADED определяют контекст тестирования проверки, когда view определен в терминах другого view. Ключевое слово ограничивает LOCAL CHECK OPTION только определяемым view. CASCADED задает проверку для основных view, которые также будут оценены. Когда никакое ключевое слово не дано, значение по умолчанию: CASCADED. Рассмотрите определения для следующей таблицы и набора view:

        mysql> CREATE TABLE t1 (a INT);
        mysql> CREATE VIEW v1 AS SELECT * FROM t1 WHERE a < 2
            ->        WITH CHECK OPTION;
        mysql> CREATE VIEW v2 AS SELECT * FROM v1 WHERE a > 0
            ->        WITH LOCAL CHECK OPTION;
        mysql> CREATE VIEW v3 AS SELECT * FROM v1 WHERE a > 0
            ->        WITH CASCADED CHECK OPTION;
        

        Здесь view v2 и v3 определены в терминах другого view, а именно v1. v2 имеет опцию проверки LOCAL, так что вставки проверены только для v2. v3 имеет опцию проверки CASCADED, так что вставки проверены не только по собственной проверки, но и для таковых основных view. Следующие инструкции иллюстрируют эти различия:

        mysql> INSERT INTO v2 VALUES (2);
        Query OK, 1 row affected (0.00 sec)
        mysql> INSERT INTO v3 VALUES (2);
        ERROR 1369 (HY000): CHECK OPTION failed 'test.v3'
        

        На обновляемость view можно воздействовать значением переменной системы updatable_views_with_limit. Команда CREATE VIEW была добавлена в MySQL 5.0.1. WITH CHECK OPTION было выполнено в MySQL 5.0.2.

        7.3. Синтаксис DROP VIEW

        DROP VIEW [IF EXISTS]
             view_name [, view_name] ...
             [RESTRICT | CASCADE]
        

        DROP VIEW удаляет один или большее количество view. Вы должны иметь привилегию DROP для каждого view. Если любой из view, именованных в списке параметров не существует, MySQL возвращает индикацию ошибки с именем, которые не существует, но удаляет все view в списке, которые существуют.

        Предложение IF EXISTS предотвращает ошибку для просмотров, которые не существуют. Когда это предложение дано, NOTE будет сгенерировано для каждого несуществующего view.

        RESTRICT и CASCADE, если заданы, анализируются и игнорируются. Эта инструкция была добавлена в MySQL 5.0.1.

        7.4. MySQL 5.1 FAQ Views

        7.4.1: Имеется ли форум для обсуждения MySQL Views?

        Да. http://forums.mysql.com/list.php?100

        7.4.2: Что случается с view, если основная таблица удалена или переименована?

        После создания view, возможно удалить или изменить таблицу (или view), к которому обращается определение. Чтобы проверять определение view для выявления проблем этого вида, используйте инструкцию CHECK TABLE.

        7.4.3: MySQL 5.1 имеет кадры таблицы?

        Нет.

        7.4.4: MySQL 5.1 имеет осуществленные views?

        Нет.

        7.4.5: Можно ли вставлять во views, которые основаны на объединениях?

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

        SELECT c1, c2 FROM t WHERE c3 > 100;

        Пример 1: Предположим, что мы выдаем эту инструкцию:

        SELECT * FROM v_merge;
        

        MySQL обрабатывает инструкцию следующим образом:

        • v_merge становится t.

        • * становится vc1, vc2, которые