Имя: Пароль:
IT
 
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
особо в запрос не вникал, но джойны "тяжелые" могут быть
иногда полное соединение и куча фильтров отрабатывает быстрее
типа такого что-то:

SELECT Goods.Charact AS Charact, GoodsStock.QTY AS QTY
FROM Goods AS CurrentCode, Goods, GoodsStock
WHERE CurrentCode.Barcode = :Barcode
AND GoodsStock.StorageID = :StorageID
AND CurrentCode.Code = Goods.Code
AND Goods.Barcode = GoodsStock.Barcode
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 продавцам в магазине =_=
Здесь можно обсудить любую тему при этом оставаясь на форуме для 1Сников, который нужен для работы. Ymryn