我有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点的IN子句可能非常大(比如75 000大),所以我有很多机会得到超时或类似“已达到表达式服务限制”
你有没有这样的事情,你是如何避免它的?
PS: 上下文:SQL server 2005,.net 2.0 (请不要告诉我我的设计不好,或者我不应该“选择*”,我只是简化了我的问题,所以它比描述我公司的500页更简单。)
感谢。
答案 0 :(得分: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与JOIN与EXISTS的区别 - great article here.
答案 1 :(得分:1)
请勿在{{1}}子句中使用显式值列表。相反,写下你的查询
IN
答案 2 :(得分:1)
最后得到我的答案:表变量(有点像@ smirkingman的解决方案,但没有cte)所以:
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#我使用类sqldatareader的ExecuteReader,Read和NextResult
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.aspx
我得到了我想要的一切: - 我的数据 - 我没有太多数据(与加入的解决方案不同) - 我不执行两次相同的查询(如子查询解决方案) - 我不必更改我的映射代码(1row = 1业务对象)
答案 3 :(得分:0)
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 :(得分: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%'"
答案 5 :(得分:0)
首先是一些代码...
使用JOIN:
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
根据表的索引编制情况,可以使用两者。其他人建议的内部联接在执行查询和返回3个表的所有数据时肯定是高效的。如果您只需要使用来自table_product
和table_period
的ID,那么使用嵌套的“IN”语句可以很好地调整索引表上的搜索条件(如果使用的标准是,则使用IN可以正常像我这样的整数假设你的FK_ID_product是。)
要记住的一件重要事情是每个数据库和关系表设置的行为都不同,在一个db到另一个db中不会有相同的优化结果。尝试手头的所有可能性,并使用最适合您的。当您需要检查性能时,查询分析器在这些时候非常有用。
当我们尝试通过ID连接和基于链接表的条件将客户帐户连接到相应的地址时,我遇到了这种情况(我们有另一个表格显示客户使用某些设备,我们必须对其进行字符串搜索。)奇怪的是,我们在一个查询中使用这两种方法的速度更快:
- 使用WH子描述'%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的文章链接,绝对是一个很好的资源。
答案 6 :(得分: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
)
......只是一个建议......