Я задаюсь вопросом о наилучшем способе создания отчетов mysql в больших базах данных, поскольку у меня есть база данных для приложения POS, над которой работает более 40 магазинов.
База данных имеет более 1,5 млн строк для каждой из четырех таблиц.
два для заголовков и другой для деталей.
Я создаю отчеты, объединяя заголовки с деталями и некоторые другие таблицы, чтобы получить полную информацию для представления.
Я попытался заархивировать данные в одной таблице, в которой есть все данные, необходимые для создания отчетов, но я обнаружил, что это огромная нагрузка, и события MySQL для извлечения данных в эту таблицу не всегда работают и могут привести к потере данных.
Я также пробовал индексировать таблицы, но это не слишком помогло, поскольку запросы слишком велики и занимают слишком много времени, что приводит к большой нагрузке на сервер и может привести к тому, что приложение вообще не отвечает.
Я искал в Google и нашел несколько идей о секционировании таблиц и других об архивировании, изменении всего движка или даже обновлении требований к серверу.
Отношение между двумя таблицами (invoice_header и invoice_detail) таково (один ко многим), что invoice_header является заголовком счета-фактуры только с итогами. Который связан с invoice_detail, используя идентификатор местоположения (loc_id) и номер счета-фактуры (invo_no), так как каждое местоположение имеет свой серийный номер. Деталь счета-фактуры содержит детали каждого счета-фактуры.
Пример запроса:
Запрос занимает слишком много (15 — 20) секунд для получения
-Всего строк: 1495873
-Всего выбранных строк: 9 — 12
SELECT SUM(invoice_detail.qty) AS qty, Month(invoice_header.date) AS month
FROM invoice_detail
JOIN invoice_header ON invoice_detail.invo_no = invoice_header.invo_no
AND invoice_detail.loc_id = invoice_header.loc_id
WHERE invoice_detail.item_id = {$itemId}
GROUP BY Month(invoice_header.date)
ORDER BY Month(invoice_header.date)
EXPLAIN:
Структура таблицы invoice_header:
CREATE TABLE `invoice_header` (
`invo_type` varchar(1) NOT NULL,
`invo_no` int(20) NOT NULL AUTO_INCREMENT,
`invo_code` varchar(50) NOT NULL,
`date` date NOT NULL,
`time` time NOT NULL,
`cust_id` int(11) NOT NULL,
`loc_id` int(3) NOT NULL,
`cash_man_id` int(11) NOT NULL,
`sales_man_id` int(11) NOT NULL,
`ref_invo_no` int(20) NOT NULL,
`total_amount` decimal(19,2) NOT NULL,
`tax` decimal(19,2) NOT NULL,
`discount_amount` decimal(19,2) NOT NULL,
`net_value` decimal(19,2) NOT NULL,
`split` decimal(19,2) NOT NULL,
`qty` int(11) NOT NULL,
`payment_type_id` varchar(20) NOT NULL,
`comments` varchar(255) NOT NULL,
PRIMARY KEY (`invo_no`,`loc_id`)
) ENGINE=InnoDB AUTO_INCREMENT=20286 DEFAULT CHARSET=utf8
Структура таблицы invoice_detail:
CREATE TABLE `invoice_detail` (
`invo_no` int(11) NOT NULL,
`loc_id` int(3) NOT NULL,
`serial` int(11) NOT NULL,
`item_id` varchar(11) NOT NULL,
`size_id` int(5) NOT NULL,
`qty` int(11) NOT NULL,
`rtp` decimal(19,2) NOT NULL,
`type` tinyint(1) NOT NULL,
PRIMARY KEY (`invo_no`,`loc_id`,`serial`),
KEY `item_id` (`item_id`),
KEY `size_id` (`size_id`),
KEY `invo_no` (`invo_no`),
KEY `serial` (`serial`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
После добавления «Извлечь»:
EXPLAIN SELECT SUM( invoice_detail.qty ) AS qty, Month( invoice_header.date ) AS
MONTH
FROM invoice_detail
JOIN invoice_header ON invoice_detail.invo_no = invoice_header.invo_no
AND invoice_detail.loc_id = invoice_header.loc_id
WHERE invoice_detail.item_id =11321
GROUP BY EXTRACT(
YEAR_MONTH FROM invoice_header.date )
Я использую неплохой выделенный сервер с:
Intel Xeon Quad Core 3.3GHz (8 threads)
1 Gbps Uplink
16 GB RAM
1,000 GB RAID-1 Drives
25 TB Bandwidth
Какие-либо предложения?
Задача ещё не решена.
Других решений пока нет …