Как правильно индексировать атрибуты в базе данных WordPress - PullRequest
0 голосов
/ 01 апреля 2020

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

$table_schema = [
        "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}plugin_orders` (
          `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
          `people_id` bigint(20) DEFAULT NULL,
          `order_id` bigint(20) DEFAULT NULL,
          `order_status` varchar(11) DEFAULT NULL,
          `order_date` datetime DEFAULT NULL,
          `order_total` decimal(13,2) DEFAULT NULL,
          `accounting` tinyint(4) DEFAULT '0',
          PRIMARY KEY (`id`),
          KEY `people_id` (`people_id`),
          KEY `order_id` (`order_id`)
        ) $collate;",

        "CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}plugin_order_product` (
          `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
          `order_id` bigint(20) DEFAULT NULL,
          `product_id` bigint(20) DEFAULT NULL,
          PRIMARY KEY (`id`),
          KEY `order_id` (`order_id`),
          KEY `product_id` (`product_id`)
        ) $collate;"
    ];

Я вижу, что id в каждой таблице - это PRIMARY KEY, но что на самом деле делает объявление других KEY? Я читал, что WordPress использует MyISAM, который на самом деле не создает соединения с внешним ключом. Хотя эти таблицы могут указывать на другие таблицы, уже существующие, в этом примере объявление KEY order_id (order_id) создает переменную сортов order_id, на которую может ссылаться любая другая таблица? Этот код специально соединяет атрибуты одной таблицы с атрибутами другой таблицы (это не так)? После того, как эти таблицы построены, я могу проверить их в phpMyAdmin и увидеть, что назначены индексы, но нет ограничений внешнего ключа. Как этот код создает таблицы, которые указывают одну таблицу на другую для построения отношений?

1 Ответ

0 голосов
/ 02 апреля 2020
KEY `foo_bar` (`order_id`)

«КЛЮЧ» совпадает с «ИНДЕКС». Он указывает, что для эффективного доступа к таблице поддерживается отдельная структура данных через столбец order_id.

foo_bar - это имя индекса. Это не имеет особого значения и имеет очень мало применений. Например, DROP KEY foo_bar; - это способ избавиться от индекса.

В MyISAM «FOREIGN KEY» разрешен, но игнорируется. В InnoDB он делает две вещи:

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

Наличие индекса важно для производительности. Приведенный выше индекс заставляет этот

SELECT ... WHERE order_id = 1234 ...

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

A PRIMARY KEY - это ключ UNIQUE, то есть INDEX.

UNIQUE(widget) говорит, что только одна строка может иметь конкретное значение `widget в таблице.

PRIMARY KEY(id) говорит о том, что каждая строка уникально идентифицируется столбцом id. InnoDB действительно хочет, чтобы каждая таблица имела PK.

"id" - это соглашение (а не требование) для имени PK. Это также INT AUTO_INCREMENT по соглашению. Вы можете или не можете когда-либо касаться id.

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

1: 1 - у них один и тот же уникальный ключ. Это редко полезно; у вас также может быть одна таблица.

1: many - в «заказе» есть несколько «предметов» (один заказ: много предметов). Обычно это делается с помощью order_id, являющегося столбцом в таблице items.

many: many - students_classes - каждый ученик учится во многих классах; В каждом классе много учеников. Это реализуется с помощью таблицы сопоставления, которая имеет (обычно) только два столбца: student_id и class_id (не требуется id) и PRIMARY KEY(student_id, class_id) и INDEX(class_id, student_id). Эти два индекса делают его эффективным для go от известного ученика до его класса, и наоборот.

Другое соглашение для PK таблицы - включение имени таблицы. (Это беспорядочно делать это для других столбцов, таких как order_status.) Я принимал это соглашение для student_id и class_id.

Но теперь меня смущает ваше plugin_orders - у него есть и id, и order_id. Если эта таблица описывает «заказы», ​​то я бы ожидал, что order_id будет PK вместо id.

И, если order_product - это список всех «продуктов» в каждом «заказе» ", тогда я ожидал бы, что у вас будет шаблон 1: много.

Какие индексы будут иметь?

  • PRIMARY KEY для уникальной идентификации каждой строки - либо id, либо некоторые столбцы (или комбинации столбцов), которые являются уникальными.
  • Другие столбцы, если необходимо, для SELECTs, UPDATEs и DELETEs, которые у вас есть. Не добавляйте индексы вслепую, пока не получите некоторые подсказки запросов, которые могут им понадобиться.

Индексы иногда помогают в сортировке:

SELECT ... ORDER BY last_name, first_name;

вместе с

INDEX(last_name, first_name)

Индексы обеспечивают производительность; ФК обеспечивают проверки целостности. Ни то, ни другое не требуется; оба «желательны».

MyISAM древний; вам нужно перейти на InnoDB.

Затем сделать что-то вроде

SELECT ...
    FROM plugin_orders AS o
    JOIN plugin_order_product AS op
           ON o.order_id = op.order_id
    WHERE ...

В этом примере оптимизатор выполнит запрос примерно так:

  1. Посмотрите на WHERE, чтобы увидеть, какую таблицу лучше всего отфильтровать по имеющимся там условиям. Объявите, что это первая таблица, с которой вы работаете.
  2. Просканируйте первую таблицу, используя индекс, если это возможно.
  3. Для каждой строки в первой таблице перейдите во вторую таблицу.
  4. Доступ ко второй таблице, вероятно, будет осуществляться через INDEX(order_id) на второй таблице. Это сделает JOIN быстрым и эффективным.

Обе таблицы имеют INDEX(order_id), но это не имеет значения.

Следующий пример:

SELECT ...
    FROM plugin_orders AS o
    JOIN plugin_order_product AS op
           ON o.order_id = op.order_id
    WHERE o.people_id = 123   -- note
  1. Выберите o в качестве первой таблицы из-за фильтрации по people_id
  2. , используйте op INDEX(people_id), чтобы быстро найти соответствующие строки o.
  3. et c (op - вторая таблица)

Следующий пример:

SELECT ...
    FROM plugin_orders AS o
    JOIN plugin_order_product AS op
           ON o.order_id = op.order_id
    WHERE op.product_id = 9887    -- changed again
  1. Выберите op в качестве первой таблицы из-за при фильтрации product_id
  2. используйте o INDEX(people_id) для быстрого поиска релевантных строк op.
  3. et c (o - вторая таблица на этот раз )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...