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 扫描的混乱情况相比。创建该索引。
我们目前正在从各种不同的来源抓取结构化数据。在将新数据引入我们的 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 扫描的混乱情况相比。创建该索引。