使用多个子查询的慢速SQL视图

时间:2013-10-29 04:49:22

标签: sql sql-server subquery sql-view correlated-subquery

创建这些视图可能有更好的方法。我的SQL体验有限,所以这就是我设计它的方式,我希望你们中的一些SQL大师可以指出我更有效的方向。

我在视图中基本上有3个表(有时是4个),这是必要的结构:

Table USER
USER_ID | EMAIL | PASSWORD | CREATED_DATE

(索引:USER_ID)

Table USER_META
ID | USER_ID | NAME | VALUE

(索引:ID,USER_ID,NAME)

Table USER_SCORES
ID | USER_ID | GAME_ID | SCORE | CREATED_DATE

(索引:ID,USER_ID)

所有表都使用第一个ID列作为自动增量主键。

第二个表“USER_META”是我保存所有联系信息和其他misc的地方。主要是first_name,last_name,street,city等。 - 根据用户的不同,这可能是4项或140,这就是为什么我使用这个表而不是在我的USER表中有150列。

对于报告,搜索和编辑,我需要来自USER_META的大约20个值,所以我的视图看起来像这样:

View V_USR_META
select USER_ID,EMAIL,
(select VALUE from USER_META 
   where NAME = 'FIRST_NAME' and USER_ID = u.USER_ID) as first_name,
(select VALUE from USER_META 
   where NAME = 'LAST_NAME'  and USER_ID = u.USER_ID) as last_name,
(select VALUE from USER_META 
   where NAME = 'CITY'  and USER_ID = u.USER_ID) as city,
(select VALUE from USER_META 
   where NAME = 'STATE'  and USER_ID = u.USER_ID) as state,
(select VALUE from USER_META 
   where NAME = 'ZIP'  and USER_ID = u.USER_ID) as zip,
    /* 10 more selects for different meta values here */
(select max(SCORE) from USER_SCORES 
   where USER_ID = u.USER_ID) as high_score,
(select top (1) CREATED_DATE from USER_SCORES 
   where USER_ID = u.USER_ID 
   order by id desc) as last_game
from USER u

这个问题很慢,实际上有更多的子查询,这只是为了说明查询。我还要查询其他一些表来获取misc。有关用户的信息。

我在搜索用户时使用该视图,搜索使用名称或用户ID或电子邮件或得分等。当我在一个地方展示所有数据时,我还使用它来填充用户信息屏幕。

那么 - 有更好的方法来编写视图吗?

2 个答案:

答案 0 :(得分:1)

所有相关子查询的替代方法是将maxcase一起使用:

select u.USER_ID,
       u.EMAIL,
       max(case when um.name = 'FIRST_NAME' then um.value end) first_name,
       max(case when um.name = 'LAST_NAME' then um.value end) last_name
       ...
from USER u
       left join USER_META um 
                on u.user_id = um.user_id
group by u.user_id, u.email

然后您可以添加user_scores结果:

select u.USER_ID,
       u.EMAIL,
       max(case when um.name = 'FIRST_NAME' then um.value end) first_name,
       max(case when um.name = 'LAST_NAME' then um.value end) last_name
       ...,
       max(us.score) maxscore,
       max(us.created_date) maxcreateddate
from USER u
       left join USER_META um 
                on u.user_id = um.user_id
       left join USER_SCORES us
                on u.user_id = us.user_id
group by u.user_id, u.email

答案 1 :(得分:0)

WITH Meta AS (
    SELECT USER_ID
          ,FIRST_NAME
          ,LAST_NAME
          ,CITY
          ,STATE
          ,ZIP
    FROM USER_META
    PIVOT (
        MAX(VALUE) FOR NAME IN (FIRST_NAME, LAST_NAME, CITY, STATE, ZIP)
    ) AS p
)
,MaxScores AS (
    SELECT USER_ID
          ,MAX(SCORE) AS Score
    FROM USER_SCORES
    GROUP BY USER_ID
)
,LastGames AS (
    SELECT USER_ID
          ,MAX(CREATED_DATE) AS GameDate
    FROM USER_SCORES
    GROUP BY USER_ID
)
SELECT USER.USER_ID
      ,USER.EMAIL
      ,Meta.FIRST_NAME
      ,Meta.LAST_NAME
      ,Meta.CITY
      ,Meta.STATE
      ,Meta.ZIP
      ,MaxScores.Score
      ,LastGames.GameDate
FROM USER
     INNER JOIN Meta
         ON USER.USER_ID = Meta.USER_ID
     LEFT JOIN MaxScores
         ON USER.USER_ID = MaxScores.USER_ID
     LEFT JOIN LastGames
         ON USER.USER_ID = LastGames.USER_ID