2010-11-23 3 views
2

У меня есть 3 таблицы:Как избежать большого предложения?

table_product (30 000 row) 
--------- 
ID 
label 

_

table_period (225 000 row) 
--------- 
ID 
date_start 
date_end 
default_price 
FK_ID_product 

и

table_special_offer (10 000 row) 
----- 
ID 
label 
date_start, 
date_end, 
special_offer_price 
FK_ID_period 

Поэтому мне нужно загружать данные из всех этих таблицы, так вот это то, что я делаю: 1/данные нагрузки из «table_product», как это

select * 
from table_product 
where label like 'gun%' 

2/загрузки данных из "table_period", как это

select * 
from table_period 
where FK_ID_product IN(list of all the ids selected in the 1) 

3/загрузки данных из "table_special_offer" как этот

select * 
from table_special_offer 
where FK_ID_period IN(list of all the ids selected in the 2) 

Как вы можете думать, что положение в в пункте 3 может быть очень большой (например, 75 000 больших), поэтому я получил много шансов получить либо тайм-аут, либо что-то вроде «Ограничение служб выражений было достигнуто».

У вас когда-нибудь было что-то подобное, и как вам удалось избежать этого?

PS: контекст: SQL сервер 2005, .net 2.0 (пожалуйста, не говорите мне, что мой дизайн плох, или я не должен делать «выбрать *», я просто упростили мою проблему, так что это немного проще, чем 500 страниц, описывающих мой бизнес).

Спасибо.

ответ

1

В конце концов у меня есть ответ: табличную переменную (немного как @ решение smirkingman, но не с КТР) так:

declare @product(id int primary key,label nvarchar(max)) 
declare @period(id int primary key,date_start datetime,date_end datetime,defaultprice real) 
declare @special_offer(id int,date_start datetime,date_end datetime,special_offer_price real) 

insert into @product 
select * 
from table_product 
where label like 'gun%' 

insert into @period 
select * 
from table_period 
where exists(
select * from @product p where p.id = table_period.FK_id_product 
) 

insert into @special_offer 
select * 
from table_special_offer 
where exists(
select * from @period p where p.id = table_special_offer.fk_id_period 
) 

select * from @product 
select * from @period 
select * from @special_offer 

это для SQL, и C# Я использую ExecuteReader, чтение и NextResult класса SqlDataReader

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx

Я получил все, что я хочу: - мои Данные - я не слишком много данных (в отличие от решений с присоединиться) - я не выполняются два раза один и тот же запрос (например, решение с подзапрос) - мне не нужно менять код отображения (1row = 1 бизнес-объект)

1

Не используйте явный список значений в предложении IN. Вместо этого напишите свой запрос, как

... FK_ID_product IN (select ID 
from table_product 
where label like 'gun%') 
+1

Не поможет. – gbn 2010-11-23 10:24:05

+0

, что было бы решением, возможно, с существующим вместо (se @atathedev link). но проблема здесь заключается в том, что это решение было бы эффективным, если бы у меня было много продукта/периода, если я выберу только несколько, я лучше сделаю явное. – 2010-11-23 10:25:40

+0

@gbn Ухаживать за разъяснением? – 2010-11-23 10:25:44

0

A JOIN дает вам те же результаты.

SELECT so.Col1 
     , so.Col2 
FROM table_product pt 
     INNER JOIN table_period pd ON pd.FK_ID_product = pt.ID_product 
     INNER JOIN table_special_offer so ON so.FK_ID_Period = pd.ID_Period 
WHERE pt.lable LIKE 'gun%' 
4

Переключение на использование объединений:

SELECT <FieldList> 
FROM Table_Product prod 
    JOIN Table_Period per ON prod.Id = per.FK_ID_Product 
    JOIN Table_Special_Offer spec ON per.ID = spec.FK_ID_Period 
WHERE prod.label LIKE 'gun%' 

Что-то вы должны быть осведомлены о том, разница IN против РЕГИСТРИРУЙТЕСЬ против EXISTS - great article here.

0
SELECT * 
    FROM 
     table_product tp 
     INNER JOIN table_period tper 
      ON tp.ID = tper.FK_ID_product 
     INNER JOIN table_special_offer so 
      ON tper.ID = so.FK_ID_period 
    WHERE 
     tp.label like 'gun%'" 
0

Первый код ...

ССПОСОЙ:

SELECT 
    table_product.* --'Explicit table calls just for organisation sake' 
, table_period.* 
, table_special_offer.* 
    FROM 
     table_product 
     INNER JOIN table_period 
      ON table_product.ID = table_period.FK_ID_product 
     INNER JOIN table_special_offer 
      ON table_period.ID = table_special_offer.FK_ID_period 
    WHERE 
     tp.label like 'gun%'" 

Использование IN:

SELECT 
    * 
FROM 
    table_special_offer 
WHERE FK_ID_period IN 
    (
    SELECT 
     FK_ID_period 
    FROM 
     table_period 
    WHERE FK_ID_product IN 
     (
     SELECT 
      FK_ID_product 
     FROM 
      table_product 
     WHERE label like '%gun' 
     ) AS ProductSub 
    ) AS PeriodSub 

В зависимости от того, насколько хорошо ваши таблицы индексируется как можно использовать. Внутренние соединения, как предлагали другие, определенно эффективны при выполнении вашего запроса и возвращении всех данных для трех таблиц. Если вам нужно только использовать идентификаторы от table_product и table_period, то использование вложенных инструкций «IN» может быть полезно для адаптации критериев поиска в индексированных таблицах (использование IN может быть в порядке, если используемые критерии являются целыми числами, как я предполагаю, что ваш FK_ID_product) ,

Важно помнить, что каждая база данных и настройка реляционных таблиц будут действовать по-другому, вы не будете иметь одинаковые оптимизированные результаты в одном db для другого. Попробуйте ВСЕ возможности и используйте тот, который вам лучше всего подходит. Анализатор запросов может быть невероятно полезен в такие моменты, когда вам нужно проверить производительность.

У меня была такая ситуация, когда мы пытались объединить счета клиентов с их соответствующими адресами через соединение ID и связанное с таблицей условие (у нас была другая таблица, в которой показывались клиенты с определенным оборудованием, которое мы должны были выполнять для поиска по строкам .) Как ни странно, нам было проще использовать оба метода в одном запросе:

- Запрос с WHERE Desc LIKE '% Equipment%' был «присоединен» к таблице клиентов с использованием предложения IN и затем он был присоединен к таблице адресов:

SELECT 
    Address.* 
, Customers_Filtered.* 
FROM 
    Address AS Address 
INNER JOIN 
    (SELECT Customers.* FROM Customers WHERE ID IN (SELECT CustomerID FROM Equipment WHERE Desc LIKE '%Equipment search here%') AS Equipment) AS Customers_Filtered 
ON Address.CustomerID = Customers_Filtered.ID 

Этот стиль запроса (прошу прощения, если мой синтаксис не совсем корректный) оказался более эффективным и легче организовать после того, как общий запрос стал более сложным.

Надеюсь, это помогло - Следите за ссылками на статью @AdaTheDev, безусловно, хороший ресурс.

0

мне было бы интересно знать, если это может сделать улучшение:

WITH products(prdid) AS (
    SELECT 
     ID 
    FROM 
     table_product 
    WHERE 
     label like 'gun%' 
), 
periods(perid) AS (
    SELECT 
     ID 
    FROM 
     table_period 
     INNER JOIN products 
      ON id = prdid 
), 
offers(offid) AS (
    SELECT 
     ID 
    FROM  
     table_special_offer 
     INNER JOIN periods 
      ON id = perid 
) 

... просто предложение ...

Смежные вопросы