Howdie сделать,Как оптимизировать запрос SQL, который соединяет 3 таблицы
Я следующий SQL-запрос, который занимает около 4 секунд для запуска:
select
o.id, tu.status_type, m.upload_date
from
(select order_id, max(last_updated) as maxudate from tracking_update group by order_id) t
inner join
tracking_update tu on t.order_id=tu.order_id and t.maxudate=tu.last_updated
right join
fgw247.order o on t.order_id=o.id
left join
manifest m on o.manifest_id=m.id
where
(m.upload_date >= '2015-12-12 00:00:00') or (m.upload_date <='2015-12-12 00:00:00' and tu.status_type != 'D' and tu.status_type != 'XD')
Запрос присоединяется следующие 3 таблицы:
Порядок, манифест и отслеживание_обмена.
Запрос будет возвращать заказы, которые отвечают следующим критериям:
- Заказы < 30 дней с любым статусом доставки
- Заказы> 30 дней, а не статус доставки
Приказ есть считается, что если последний параметр отслеживания_загрузки для этого заказа имеет статус_тип 'D' или 'XD'
Теперь заказы перечислены в таблицу заказа. В таблице Order есть столбец с именем manifest_id, который ссылается на манифест, который был создан при заказе заказа.
манифест может иметь несколько заказов. Это то, что используется для определения того, был ли заказ загружен за последние 30 дней.
И наконец, таблица tracking_update содержит отслеживание_updates за заказ. В заказе может быть несколько параметров отслеживания.
В настоящее время таблица tracking_update имеет длину более 1M.
Ниже перечислены создания заявления для каждой таблицы:
CREATE TABLE "order" (
"id" int(11) NOT NULL AUTO_INCREMENT,
"ShipmentId" varchar(50) DEFAULT NULL,
"RecipientName" varchar(160) DEFAULT NULL,
"CompanyName" varchar(160) DEFAULT NULL,
"Address1" varchar(160) DEFAULT NULL,
"Address2" varchar(160) DEFAULT NULL,
"City" varchar(50) DEFAULT NULL,
"State" varchar(3) DEFAULT NULL,
"ZIP" int(11) DEFAULT NULL,
"TEL" int(11) DEFAULT NULL,
"Email" varchar(255) DEFAULT NULL,
"Bottles" int(11) DEFAULT NULL,
"Weight" float DEFAULT NULL,
"Resi" tinyint(1) DEFAULT NULL,
"Wave" int(11) DEFAULT NULL,
"url_slug" varchar(50) DEFAULT NULL,
"manifest_id" int(11) DEFAULT NULL,
"shipment_date" datetime DEFAULT NULL,
"tracking_number" varchar(30) DEFAULT NULL,
"shipping_carrier" varchar(10) DEFAULT NULL,
"last_tracking_update" datetime DEFAULT NULL,
"delivery_date" datetime DEFAULT NULL,
"customer_code" varchar(50) DEFAULT NULL,
"sub_cust_code" int(11) DEFAULT NULL,
PRIMARY KEY ("id"),
UNIQUE KEY "ShipmentID" ("ShipmentId"),
KEY "manifest_id" ("manifest_id"),
KEY "order_idx3" ("tracking_number"),
KEY "order_idx4" ("customer_code"),
CONSTRAINT "order_ibfk_1" FOREIGN KEY ("manifest_id") REFERENCES "manifest" ("id")
);
Tracking_Update стол:
CREATE TABLE "tracking_update" (
"id" int(11) NOT NULL AUTO_INCREMENT,
"order_id" int(11) DEFAULT NULL,
"ship_update_date" datetime DEFAULT NULL,
"message" varchar(400) DEFAULT NULL,
"location" varchar(100) DEFAULT NULL,
"status_type" varchar(2) DEFAULT NULL,
"last_updated" datetime DEFAULT NULL,
"hash" varchar(32) DEFAULT NULL,
PRIMARY KEY ("id"),
KEY "order_id" ("order_id"),
KEY "tracking_update_idx2" ("status_type"),
KEY "tracking_update_idx3" ("ship_update_date"),
CONSTRAINT "tracking_update_ibfk_1" FOREIGN KEY ("order_id") REFERENCES "order" ("id")
);
Manifest стол:
CREATE TABLE "manifest" (
"id" int(11) NOT NULL AUTO_INCREMENT,
"upload_date" datetime DEFAULT NULL,
"name" varchar(100) DEFAULT NULL,
"destination_gateway" varchar(40) DEFAULT NULL,
"arrived" tinyint(1) DEFAULT NULL,
"customer_code" varchar(50) DEFAULT NULL,
"upload_user" varchar(50) DEFAULT NULL,
"trip_id" int(11) DEFAULT NULL,
PRIMARY KEY ("id")
);
Здесь также EXPLAIN на оператора выбора экспортируется с помощью JSON:
{
"data":
[
{
"id": 1,
"select_type": "PRIMARY",
"table": "m",
"type": "ALL",
"possible_keys": "PRIMARY",
"key": null,
"key_len": null,
"ref": null,
"rows": 220,
"Extra": "Using where"
},
{
"id": 1,
"select_type": "PRIMARY",
"table": "o",
"type": "ref",
"possible_keys": "manifest_id",
"key": "manifest_id",
"key_len": "5",
"ref": "fgw247.m.id",
"rows": 246,
"Extra": "Using index"
},
{
"id": 1,
"select_type": "PRIMARY",
"table": "tu",
"type": "ref",
"possible_keys": "order_id",
"key": "order_id",
"key_len": "5",
"ref": "fgw247.o.id",
"rows": 7,
"Extra": "Using where"
},
{
"id": 1,
"select_type": "PRIMARY",
"table": "<derived2>",
"type": "ref",
"possible_keys": "<auto_key0>",
"key": "<auto_key0>",
"key_len": "11",
"ref": "fgw247.o.id,fgw247.tu.last_updated",
"rows": 13,
"Extra": "Using index"
},
{
"id": 2,
"select_type": "DERIVED",
"table": "tracking_update",
"type": "index",
"possible_keys": "order_id",
"key": "order_id",
"key_len": "5",
"ref": null,
"rows": 1388275,
"Extra": null
}
]
}
Любая помощь приветствуется
UPDATE
Это текущий запрос, который я использую, который гораздо быстрее:
SELECT
o.*, tu.*
FROM
fgw247.`order` o
JOIN
manifest m
ON
o.`manifest_id` = m.`id`
JOIN
`tracking_update` tu
ON
tu.`order_id` = o.`id` and tu.`ship_update_date` = (select max(last_updated) as last_updated from tracking_update where order_id = o.`id` group by order_id)
WHERE
m.`upload_date` >= '2015-12-14 11:50:12'
OR
(o.`delivery_date` IS NULL AND m.`upload_date` < '2015-12-14 11:50:12')
LIMIT 100
Благодарим вас за ответ. См. Мой обновленный запрос. Я все еще не уверен, что понимаю союз. Вы хотите создать два разных оператора выбора? – Jimmy
Вы изменили соединения на внутренние соединения (это было мое первое предложение), изменили критерии (я не могу прокомментировать это, так как я не знаю ваших данных) и изменил подзапрос из производной таблицы на запрос значения. Я не могу сказать, какое изменение ускорило новую версию. – Shadow
Я знаю, что предпочитаю иметь производную версию таблицы по вашему выбору, потому что в случае производной таблицы подзапрос выполняется только один раз. С вашей версией существует риск того, что для каждой записи подзапрос выполняется отдельно. Однако, если соединения удалят большую часть записей в производной таблице, то решение в вашей обновленной версии также может быть быстрым. Я не знаю ваших данных, поэтому не могу комментировать это. – Shadow