У меня есть две простые таблицы MySQL - одна таблица индексов t_id
, которая имеет уникальный первичный идентификатор;и сводная таблица t_data
, распределяющая эти идентификаторы по различным полям данных:
CREATE TABLE `t_id` (
`id` bigint(12) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_data` (
`id` int(11) NOT NULL,
`field` varchar(50) CHARACTER SET cp1251 NOT NULL,
`value` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci
DEFAULT NULL,
UNIQUE KEY `idxfield` (`id`,`field`),
KEY `value` (`value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Вот некоторые примеры данных:
+----+--------------+-------------------+
| id | field | value |
+----+--------------+-------------------+
| 1 | organization | Apple Inc. |
| 1 | state | CA |
| 2 | organization | Adobe Inc. |
| 2 | state | CA |
| 3 | organization | Alphabet Inc. |
| 3 | state | CA |
| 4 | organization | Rockwell Collins |
| 4 | state | IA |
| 5 | organization | GEICO |
| 5 | state | MD |
| 6 | organization | Anheuser-Busch |
| 6 | state | MO |
| 7 | organization | Bank of America |
| 7 | state | NC |
+----+--------------+-------------------+
, о которых можно сообщить с помощью стандартного выбора сводной таблицыquery:
select
i.id,
ifnull (max(case when d.field = 'organization' then d.value end),'') 'organization',
ifnull (max(case when d.field = 'state' then d.value end),'') 'state'
from `t_id` i
left join `t_data` d
on i.id = d.id
group by i.id
limit 0,10
В этом простом примере показаны только два "виртуальных" поля (организация и состояние) с 7 уникальными идентификаторами:
+----+------------------+-------+
| id | organization | state |
+----+------------------+-------+
| 1 | Apple Inc. | CA |
| 2 | Adobe Inc. | CA |
| 3 | Alphabet Inc. | CA |
| 4 | Rockwell Collins | IA |
| 5 | GEICO | MD |
| 6 | Anheuser-Busch | MO |
| 7 | Bank of America | NC |
+----+------------------+-------+
В нашей реальной производственной ситуации у нас есть десятки«виртуальные» поля (не только 2) и миллионы уникальных идентификаторов (не только 7). База данных довольно хорошо выполняет запросы типа crud для одного идентификатора (менее секунды) и даже перечисляет одну группу ограничений за раз (опять же менее секунды). Проблема возникает, когда делается попытка ограничить выбор предложением where (запросы занимают десятки секунд). Например, чтобы найти все организации в Калифорнии:
select
x.id,
x.organization,
x.state
from
(
select
i.id,
ifnull (max(case when d.field = 'organization' then d.value end),'') 'organization',
ifnull (max(case when d.field = 'state' then d.value end),'') 'state'
from `t_id` i
left join `t_data` d
on i.id = d.id
group by i.id
) as x
where x.state='CA'
limit 0,10
+----+---------------+-------+
| id | organization | state |
+----+---------------+-------+
| 1 | Apple Inc. | CA |
| 2 | Adobe Inc. | CA |
| 3 | Alphabet Inc. | CA |
+----+---------------+-------+
это работает, но это занимает ДЛИННОЕ время (опять же, 10 секунд)! Какова лучшая практика здесь - есть ли лучший способ написать эти типы запросов? Как можно оптимизировать эти запросы сводной таблицы для предложения where?