SQL 服务器低效查询(服务器满载)

SQL Server inefficient query (server full load)

我们目前正在从各种不同的来源抓取结构化数据。在将新数据引入我们的 table 之前,我们检查 data_id 是否已经存在。

IF NOT EXISTS (SELECT TOP 1 * FROM TABLE_NAME WHERE DATA_ID=@P0)

我们没有索引;然而,我们为我们的 id 列设置了一个 PK,这似乎是不必要的,我们是否应该删除它以提高插入速度?

我们的服务器目前正在满负荷检查 300 万左右的数据,以确保我们没有插入重复数据。我们已尝试升级我们的 SQL 服务器以获得更高的 DTU,但这似乎根本没有帮助。

当我们有多个作业时 运行 同时检查唯一数据或 SQL 服务器开始爬行并且插入速度永远变慢。

我们是否应该摆脱这种独特的数据检查并为每个抓取作业创建新的 tables,然后使用 SQL 查询来比较差异,例如新数据或以前的数据移除了吗?

用于条件插入的查询:

String sql = "IF NOT EXISTS (SELECT TOP 1 * FROM A_PROV_CVV_LDG_1 WHERE DATA_ID=?) " +
            "INSERT INTO A_PROV_CVV_LDG_1 (DATA_ID, SourceID, BASE_ID, BIN, BANK, CARD_TYPE, CARD_CLASS," +
            " CARD_LEVEL, CARD_EXP, COUNTRY, STATE, CITY, ZIP, DOB, SSN, EMAIL, PHONE, GENDER, ADDR_LINE_1, ADDR_LINE_2," +
            " FIRST_NAME, LAST_NAME, DateAddedToMarket, PRICE) " +
            "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

这是整个table定义,没有索引只有PK是'id'这似乎是不必要的。

+-------------------+--------------+-----------+ | (PK)id | int | Unchecked | | DATA_ID | int | Checked | | SourceID | int | Checked | | BASE_ID | varchar(255) | Checked | | BIN | varchar(255) | Checked | | BANK | varchar(255) | Checked | | CARD_TYPE | varchar(255) | Checked | | CARD_CLASS | varchar(255) | Checked | | CARD_LEVEL | varchar(255) | Checked | | CARD_EXP | varchar(255) | Checked | | COUNTRY | varchar(255) | Checked | | STATE | varchar(255) | Checked | | CITY | varchar(255) | Checked | | ZIP | varchar(255) | Checked | | DOB | varchar(255) | Checked | | SSN | varchar(255) | Checked | | EMAIL | varchar(255) | Checked | | PHONE | varchar(255) | Checked | | GENDER | varchar(255) | Checked | | ADDR_LINE_1 | varchar(255) | Checked | | ADDR_LINE_2 | varchar(255) | Checked | | FIRST_NAME | varchar(255) | Checked | | LAST_NAME | varchar(255) | Checked | | PRICE | varchar(255) | Checked | | DateAddedToMarket | varchar(255) | Checked | | DateAdded | datetime | Unchecked | +-------------------+--------------+-----------+

如果服务器繁忙,语句:IF NOT EXISTS (SELECT TOP 1 * FROM TABLE_NAME WHERE DATA_ID=@P0) 可能被阻塞或磁盘请求排队. 运行 sp_who2 检查是否有阻塞。如果这是将数据放入 table 中的唯一例程,请添加 WITH (NOLOCK),选择 Null 而不是任何不必要的内容:

IF NOT EXISTS (SELECT null FROM TABLE_NAME WITH (NOLOCK) WHERE DATA_ID=@P0)

这个结构:

IF NOT EXISTS (SELECT TOP 1 * FROM A_PROV_CVV_LDG_1 WHERE DATA_ID=?)
    INSERT INTO A_PROV_CVV_LDG_1 . . .

是一个 anti-pattern。它试图防止代码重复。但是,它受到竞争条件的影响。并且您应该让数据库尽可能地执行数据完整性检查。

相反,实施唯一的 constraint/index 以防止重复:

alter table A_PROV_CVV_LDG_1 add constraint unq_A_PROV_CVV_LDG_1_data_id
    unique (data_id);

这确实意味着如果您尝试插入重复值,则需要捕获错误。这在 SQL 服务器中使用 try/catch 块很容易。

您的查询绝对需要 DATA_ID 上的唯一索引——实际上是为了让 DATA_ID 上的任何重复数据删除尝试有效地工作。没有它,每次尝试插入都会进行完整的 table 扫描。

是的,索引会稍微减慢插入速度。但是整数列上的索引并不是很昂贵。当然不能与您现在对每个插入进行 table 扫描的混乱情况相比。创建该索引。