|
SQL, Помогите оптимизировать запрос | ☑ | ||
---|---|---|---|---|
0
rutony
04.09.13
✎
12:19
|
Нужно отобрать все характеристи с количеством товара по штрихкоду. То есть ищем в справочнике (Goods) штрихкод, получаем код товара, ищем по коду товара все штрихкоды (Goods) (1 штрихкод на 1 характеристику) и по найденным штрихкодам ищем на определенном складе остатки (GoodsStock).
Структура таблиц: CREATE TABLE Goods ( Barcode CHAR( 13 ) PRIMARY KEY, InnerCode CHAR( 15 ), Name CHAR( 150 ), Charact CHAR( 15 ), Price INTEGER( 10, 2 ), Code CHAR( 11 ), Discount INTEGER( 10, 2 ) ); CREATE TABLE GoodsStock ( Barcode CHAR( 13 ), StorageID CHAR( 9 ), QTY INTEGER( 10, 2 ) ); В обоих таблицах есть индексы по штрихкодам. Сам запрос... Чувствую что делает лишние выборки, но знаний по запросам скуля не хватает=\ SELECT Goods.Charact AS Charact, GoodsStock.QTY AS QTY FROM Goods AS CurrentCode LEFT OUTER JOIN Goods ON CurrentCode.Code = Goods.Code LEFT OUTER JOIN GoodsStock ON Goods.Barcode = GoodsStock.Barcode WHERE CurrentCode.Barcode = :Barcode AND GoodsStock.StorageID = :StorageID |
|||
1
rutony
04.09.13
✎
12:23
|
Сам запрос рабочий, просто база на 100 тыс. записей, и остатки под 500 тыс. записей.
На ББ запрос делает пару долей секунд... А вот на ТСД, уже хуже нет таких мощностей, запрос делается 4-5 секунды=\ |
|||
2
ДенисЧ
04.09.13
✎
12:24
|
А причём тсд и скорость запроса?
Он же выполняется на сервере... Или у тебя обработка на клиенте идёт? Выноси на сервер... |
|||
3
dk
04.09.13
✎
12:25
|
на тсд своя копия базы?
|
|||
4
MrStomak
04.09.13
✎
12:26
|
ну например у тебя условие AND GoodsStock.StorageID = :StorageID в соединении должно быть
|
|||
5
rutony
04.09.13
✎
12:27
|
(2) На ТСД своя локальная скуль база. Он для автономной работы, для проведения инвентаризации и тд, тп...
|
|||
6
MrStomak
04.09.13
✎
12:28
|
и вообще, если я правильно понимаю, то таблица GoodsStock соединяется с CurrentCode, а условие по баркоду на Goods =\
|
|||
7
kortun
04.09.13
✎
12:28
|
LEFT OUTER JOIN Goods
ON CurrentCode.Code = Goods.Code а зачем это соединение? |
|||
8
НеБорис Нуралиев
04.09.13
✎
12:28
|
А зачем таблицу джойнить к самой себе?
В запросе должен быть один INNER JOIN и ничего более. Еще можешь кластерных индексов на BARCODE в обоих базах накидать. |
|||
9
MrStomak
04.09.13
✎
12:28
|
Может так надо?:
LEFT OUTER JOIN Goods LEFT OUTER JOIN GoodsStock ON Goods.Barcode = GoodsStock.Barcode ON CurrentCode.Code = Goods.Code |
|||
10
НеБорис Нуралиев
04.09.13
✎
12:32
|
Можно попытаться сделать так:
SELECT Goods.Charact AS Charact, GoodsStock.QTY AS QTY FROM Goods AS Goods INNER JOIN GoodsStock AS GoodsStock ON Goods.Barcode = GoodsStock.Barcode AND Goods.Barcode = :Barcode AND GoodsStock.StorageID = :StorageID |
|||
11
rutony
04.09.13
✎
12:34
|
(7) У товара много характеристик, нужно вывести остатки по всем характеристикам, а не только отсканированного штрихкода.
|
|||
12
dk
04.09.13
✎
12:35
|
особо в запрос не вникал, но джойны "тяжелые" могут быть
иногда полное соединение и куча фильтров отрабатывает быстрее типа такого что-то:
|
|||
13
SnarkHunter
04.09.13
✎
12:35
|
(10)Этот запрос не решает задачу. Здесь выборка только для одного считанного штрихкода, а у товара штрихкодов м.б. несколько. Это в условии написано.
|
|||
14
rutony
04.09.13
✎
12:35
|
(10) Сразу нет, нужен остаток не по штрихкоду, а всем характеристикам товара.
|
|||
15
АНДР
04.09.13
✎
12:36
|
(10) Первым запросом получать товар. Отработает по индексу.
Потом Джойнить склад с баркодами по условию на совпадение баркодов и равенства кода товара полученному на первом шаге. |
|||
16
rutony
04.09.13
✎
12:43
|
(12) Замер не показал разницы с исходным запросом
Оригинальный: 3 row(s) read in 0.015451 second(s). Твой: 3 row(s) read in 0.015523 second(s). |
|||
17
dk
04.09.13
✎
12:51
|
(16) дык ты на ТСД замеры делаешь?
|
|||
18
rutony
04.09.13
✎
13:10
|
(16) Хм, да что то туплю, щас попробую на ТСД.
|
|||
19
badboychik
04.09.13
✎
13:11
|
а индекс по полю Code есть?
|
|||
20
rutony
04.09.13
✎
13:14
|
(19) Нету. Я посчитал, что лучше не делать лишние индексы, база иначе сильно растет. Без индексов 15 мб, с индексами по ШК 24 мб. И время загрузки на терминале выросла почти в 2 раза...
|
|||
21
badboychik
04.09.13
✎
13:19
|
(20) пусть время загрузки вырастет, зато поиск будет быстрее.
Там такой маленький объем памяти что ли, каждый МБ считаешь?? |
|||
22
rutony
04.09.13
✎
13:26
|
(21) Ну да, сильные ограничения. Терминал самый дешевый, постой на WinCE.
|
|||
23
badboychik
04.09.13
✎
13:38
|
SELECT INTO #tmp
Goods.Charact AS Charact, Goods2.BarCode AS BarCode FROM Goods LEFT JOIN Goods AS Goods2 ON Goods.Code = Goods2.Code WHERE Goods.Barcode = :Barcode ; SELECT #tmp AS Goods, GoodsStock.QTY AS QTY FROM #tmp AS Goods LEFT JOIN GoodsStock ON Goods.Barcode = GoodsStock.Barcode WHERE GoodsStock.StorageID = :StorageID |
|||
24
trad
04.09.13
✎
13:41
|
Сделать кластерный PK (Barcode) on Goods
и кластерный PK (Barcode,StorageID) on GoodsStock - кластерные индексы не приведут к увеличению размера базы. Сделать индекс (Code) on Goods |
|||
25
trad
04.09.13
✎
13:42
|
PK - PRIMARY KEY
|
|||
26
МихаилМ
04.09.13
✎
13:43
|
меня INTEGER( 10, 2 ) смущает.
какая субд |
|||
27
ptiz
04.09.13
✎
13:52
|
Если с временными таблицами, то я бы сделал так:
сначала выбираем только нужные характеристики и штрихкоды в маленькую табличку и дальше работаем уже ней SELECT INTO #tmpGoods Goods.Charact AS Charact, Goods.Barcode AS Barcode FROM Goods AS Goods WHERE Goods.Code IN (SELECT Goods.Code FROM Goods WHERE Goods.Barcode = :Barcode) ; SELECT Goods.Charact AS Charact, GoodsStock.QTY AS QTY FROM #tmpGoods AS Goods INNER JOIN (SELECT GoodsStock.QTY, GoodsStock.Barcode FROM GoodsStock WHERE GoodsStock.StorageID = :StorageID and GoodsStock.Barcode IN (SELECT Goods.Barcode FROM #tmpGoods as Goods)) as GoodsStock ON Goods.Barcode = GoodsStock.Barcode |
|||
28
rutony
04.09.13
✎
13:55
|
(23) (26) (27)
Sqlite3. К сожалению, ее функциональность ограничена в плане виртуальных таблиц. Переделал немного (23), сделал вложенный запрос, вместо виртуальной таблицы. Разницы никакой... Ладно, придется оставить 4-5 секундный поиск, для режима "Проверка ценника" не так критично. |
|||
29
badboychik
04.09.13
✎
13:57
|
(27) че за монстр? я же написал в (23) уже, зачем все эти IN и вложенные запросы, если штрихкоды уже лежат в поле временной таблицы и их не надо искать заново подзапросами
|
|||
30
ptiz
04.09.13
✎
14:02
|
(29) Имхо, в (23) всё тормозит то же самое FROM Goods LEFT JOIN Goods
(28) Тады так: SELECT Goods.Charact AS Charact, GoodsStock.QTY AS QTY FROM Goods AS Goods INNER JOIN GoodsStock ON Goods.Barcode = GoodsStock.Barcode and GoodsStock.StorageID = :StorageID WHERE Goods.Code IN (SELECT Goods.Code FROM Goods WHERE Goods.Barcode = :Barcode) |
|||
31
badboychik
04.09.13
✎
14:32
|
А там в терминале только один запрос можно использовать или процедуру на каком то языке писать можно?
|
|||
32
АНДР
04.09.13
✎
14:45
|
(30) С чего это перенос подзапроса в Where из условия объединения ускорит выполнение!?
(0) Если одному баркоду (а разьве бывает иначе) сопоставлен один товар, то задачу нужно разбивать на две. 1) Определять товар, 2) по товару определять остатки. А не собирать мегатаблицу для выдёргивания из неё остатков по нужному баркоду. |
|||
33
ptiz
04.09.13
✎
14:47
|
(32) "С чего это перенос подзапроса в Where из условия объединения ускорит выполнение!?" - можно и так, и так.
Как быстрее - надо тестить. |
|||
34
Salimbek
04.09.13
✎
15:03
|
ИМХО, (24) самое выгодное
|
|||
35
trad
04.09.13
✎
15:22
|
(34) но, увы, как оказалось имеем дело с sqlite, а там нет кластерных индексов.
|
|||
36
trad
04.09.13
✎
15:26
|
Нужны индексы про которые я сказал, иначе ускорения не добиться.
Но, ввиду отсутствия кластерных, нужно пожертвовать местом для обычных индексов, на что ТС пойти не может. |
|||
37
BigHarry
04.09.13
✎
15:50
|
А BarCode нельзя выразить как-то в число, а то ключи по символьным - не есть гуд...
|
|||
38
Serginio1
04.09.13
✎
16:04
|
(0) Проще соединение через Wi-Fi использовать. А без индексов тебе никуда не деться, а что и внешнюю память подключить нельзя?
|
|||
39
rutony
04.09.13
✎
16:12
|
(37) Штрихкоды могут быть специфическими, в том числе с ведущими нулями, или даже с символами.
(31) Не совсем понимаю о чем речь... Пишу на лазариусе, для хранения использую sqlite... (38) 1с сидит в терминальном сервере, а магазины разбросаны по городу и области. Постоянного коннекта может и не быть. У конкретно этой модели есть, но реализация проекта не завязана на конкретный терминал, софтина может работать на любом (с рядом условий) терминале. Я ж написал, что пока оставлю так, если будут жаловаться воткну еще индекс по коду товара... Просто загрузка данных на терминал не очень кашерно.. |
|||
40
Serginio1
04.09.13
✎
16:17
|
(39) Ну можно добавить опционально к какой базе подключаться, которую можно организовать на любом компьютере или к глобальной по HTTP (переопределить только строку подключения)
|
|||
41
arsik
гуру
04.09.13
✎
17:26
|
(39) А напрямую в ТСД писать базу нельзя?
Сейчас у тебя загружается построчно + уже на тсд создаются индексы. А нельзя заранее базу с индексами создать и отдать уже готовую в ТСД? |
|||
42
rutony
04.09.13
✎
17:34
|
(41) Можно, программа кросплатформенная, можно под виндой запустить и загрузить, это займет пару секунд, ну и копирование 4-5 минут.
НО попробуй объясни, что делать 20 продавцам в магазине =_= |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |