非常长的“不在”请求

时间:2015-04-14 07:40:46

标签: sql sql-server database performance query-performance

我有两张桌子:

  1. "会话" - 它具有int密钥标识," session_id" - varchar," device_category" - varchar和其他一些colums。 有149239行。

  2. Session_events" - 它有int键 身份," session_id" - uniqueidentifier和其他一些领域。 那里有3140768行。

  3. 此表已从非关系数据库导入 - Cassandra,因此我没有在MS SQL Server设计器中创建任何连接。但是,在session_id列上的Sessions和Session_events之间的真正连接是“多对多”

    现在我要删除所有未在个人计算机" device_category"上发生的网络会话。所以我运行请求Delete * FROM sessions where device_category != "PC" 那很快。现在我想从Session_events表中删除所有不是PC会话。所以我运行请求

    Delete FROM session_events where session_id Not In (SELECT distinct session_id FROM sessions)
    

    该请求目前运行超过24小时,我不知道可以花多长时间......

    (我有16 GB ram和Intel Xenon)。

    我知道Left Join可以更快,但20%不是很有趣。你看到了更快完成任务的方法吗?

    ----
    CREATE TABLE [dbo].[session_events](
        [key] [bigint] IDENTITY(1,1) NOT NULL,
        [session_id] [uniqueidentifier](max) NULL,
        [visitor_id] [uniqueidentifier] NULL,
        [shipping_method] [varchar](max) NULL,
        [shipping_price] [varchar](max) NULL,
        [site_id] [int] NULL,
        [stream_data_chunk] [varbinary](max) NULL,
        [total] [varchar](max) NULL,
        [total_inc_tax] [varchar](max) NULL,
        [tracker_ver] [varchar](max) NULL
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    

    CREATE TABLE [dbo].[visitor_sessions](
        [key] [int] IDENTITY(1,1) NOT NULL,
        [visitor_id] [varchar](max) NULL,
        [created] [varchar](max) NULL,
        [session_id] [varchar](max) NULL
    )
    
     CONSTRAINT [PK_visitor_sessions4] PRIMARY KEY CLUSTERED 
    (
        [key] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    
    GO
    
    SET ANSI_PADDING OFF
    GO
    

5 个答案:

答案 0 :(得分:4)

一次删除大量数据意味着数据库引擎必须在单个事务中完成所有这些操作。这意味着当你实际上不需要它时会产生巨大的开销(例如,你不需要回滚整个操作,或者你不关心一致性 - 你只想删除所有内容,如果它如果在中间失败,您只需再次运行查询以删除其余部分。

对于您的情况,您可以尝试批量删除。例如:

delete top 1000 from session_events where session_id Not In (SELECT distinct session_id FROM sessions)

重复直到表格为空。

另外,你从错误的角度出发。你可能最好先在两者之间创建一个外键,然后使用"删除级联"。这会自动删除不再具有有效session_events的所有session。如果你可以重新开始,可能明显更快。但是没有承诺:D

答案 1 :(得分:0)

为什么不使用左连接?另一种方法是使用EXISTS而不是IN:

DELETE FROM Session_events
WHERE NOT EXISTS(
    SELECT 1
    FROM Session 
    WHERE Session.Session_Id = Session_events.Session_Id
)

答案 2 :(得分:0)

有时删除的问题是等待获取所有相关行的锁定。尝试在循环中删除。

DECLARE @MyCursor CURSOR;
DECLARE @MyField YourFieldDataType;//replace with the data type of session_id
BEGIN
    SET @MyCursor = CURSOR FOR
    select session_id from session_events minus select session_id from sessions
    OPEN @MyCursor 
    FETCH NEXT FROM @MyCursor 
    INTO @MyField
    WHILE @@FETCH_STATUS = 0
    BEGIN
        delete session_events where session_id = @MyField
        FETCH NEXT FROM @MyCursor 
        INTO @MyField 
    END;
    CLOSE @MyCursor ;
    DEALLOCATE @MyCursor;
END;

您还可以尝试将not in重写为in

delete from session_events where session_id in (select session_id from session_events minus select session_id from sessions)

答案 3 :(得分:-1)

  1. 检查session_event中是否有索引?如果有,则禁用它
  2. 使用NOT EXISTS而不是NOT IN,因为EXISTS的性能优于其他(如@Zohar Peled写的查询)
  3. 如果未解决,则单独运行您的选择查询并查看执行计划,以了解执行Select时将要执行的操作。

答案 4 :(得分:-2)

试试这段代码

delete e
from session_events e 
left join sessions s (nolock)
    on e.session_id = s.session_id
where s.session_id is null