Needing help to improve some TSQL "not exists" query performance - tsql

I'm having an performance issue running a query on a table containing 750 000 entries. It takes between 15 to 20 seconds to execute, blocking access to the database during that time and creating lots of error logs (and angry customers, of course).
Here is the query:
DECLARE #FROM_ID AS UNIQUEIDENTIFIER = 'XXX'
DECLARE #TO_ID AS UNIQUEIDENTIFIER = 'YYY'
update tbl_share
set user_id = #TO_ID
where user_id = #FROM_ID
and not exists (
select *
from tbl_share ts
where ts.file_id = file_id
and ts.user_id = #TO_ID
and ts.corr_id = corr_id
and ts.local_group_id = local_group_id
and ts.global_group_id = global_group_id
)
I'm kind of stuck right now since my TSQL knowledge is limited.
I'm wondering if:
I should create a temporary table
I should select something else than "*"
I haven't lot of opportunities to run the tests since it's a production database and there are permanently 10-20 customers connected on day time.
Thanks for your help!

How about restructuring your code logic?
DECLARE #FROM_ID AS UNIQUEIDENTIFIER = 'XXX'
DECLARE #TO_ID AS UNIQUEIDENTIFIER = 'YYY'
IF NOT EXISTS (select *
from tbl_share ts
where ts.user_id = #TO_ID)
BEGIN
update tbl_share
set user_id = #TO_ID
where user_id = #FROM_ID
END
So, you are doing your check beforehand and do only updating the database in the case it is needed.
HTH

Let's start with optimizing the select.
Check query plans.
If that is the PK then is it fragmented?
select *
from tbl_share
where user_id = #FROM_ID
and not exists (
select *
from tbl_share ts
where ts.file_id = file_id
and ts.user_id = #TO_ID
and ts.corr_id = corr_id
and ts.local_group_id = local_group_id
and ts.global_group_id = global_group_id
)
select tUpdate.*
from tbl_share as tUpdate
left outer join tbl_share as tExists
on tUpdate.user_id = #FROM_ID
and tExists.user_id = #TO_ID
and tExists.file_id = tUpdate.file_id
and tExists.corr_id = tUpdate.corr_id
and tExists.local_group_id = tUpdate.local_group_id
and tExists.global_group_id = tUpdate.global_group_id
where tExists.user_id is null

Related

Postgresql Update & Inner Join

I am trying to update data in Table: local.import_payments from Table: local.payments based on update and Inner Join queries. The query I used:
Update local.import_payments
Set local.import_payments.client_id = local.payments.payment_for_client__record_id,
local.import_payments.client_name = local.payments.payment_for_client__company_name,
local.import_payments.customer_id = local.payments.customer__record_id,
local.import_payments.customer_name = local.payment_from_customer,
local.import_payments.payment_id = local.payments.payment_id
From local.import_payments
Inner Join local.payments
Where local.payments.copy_to_imported_payments = 'true'
The client_id, client_name, customer_id, customer_name in the local.import_payments need to get updated with the values from the table local.payments based on the condition that the field copy_to_imported_payments is checked.
I am getting a syntax error while executing the query. I tried a couple of things, but they did not work. Can anyone look over the queries and let me know where the issue is
Try the following
UPDATE local.import_payments
Set local.import_payments.client_id =
local.payments.payment_for_client__record_id,
local.import_payments.client_name =
local.payments.payment_for_client__company_name,
local.import_payments.customer_id = local.payments.customer__record_id,
local.import_payments.customer_name = local.payment_from_customer,
local.import_payments.payment_id = local.payments.payment_id
FROM local.payments as lpay
WHERE lpay.<<field>> = local.import_payments.<<field>>
AND local.payments.copy_to_imported_payments = 'true'
You shouldn't to specify the schema/table for updated columns, only column names:
Do not include the table's name in the specification of a target column — for example, UPDATE table_name SET table_name.col = 1 is invalid.
from the doc
You shouldn't to use the updating table in the from clause except of the case of self-join.
You can to make your query shorter using "column-list syntax".
update local.import_payments as target
set (
client_id,
client_name,
customer_id,
customer_name,
payment_id) = (
source.payment_for_client__record_id,
source.payment_for_client__company_name,
source.customer__record_id,
source.payment_from_customer,
source.payment_id)
from local.payments as source
where
<join condition> and
source.copy_to_imported_payments = 'true'

Update big amount of data postgresql

The main table used is transaction, and can store million rows (let's say 4-5 million max). I need to update a status as fast as possible.
The update query looks like this :
UPDATE transaction SET transaction.status = 'TO_EXECUTE'
WHERE transaction.id IN (SELECT transaction.id FROM transaction
JOIN anotherTable ON transaction.id = anotherTable.id
JOIN anotherTable2 ON transaction.serviceId = ontherTable2.id
WHERE transaction.status = :filter1, transaction.filter2 = :filter2, ...)
Do you have a better solution? Could it be better to create another table to store the status an the id ? (I red that updating large Tables can be really slow).
The IN part of your query could likely be re-written as "exists" to potentially get improvements, depending on the other table layouts and volume. Also, it's highly possible that you do not need the transaction table mentioned yet again in the sub query (exists or in)
UPDATE transaction tx SET transaction.status = 'TO_EXECUTE'
WHERE exists (SELECT *
FROM anotherTable
JOIN anotherTable2 ON tx.serviceId = anotherTable2.id
WHERE anothertable.id=tx.id and
transaction.status = :filter1 and transaction.filter2 = :filter2,
...)
try this:
UPDATE transaction
SET transaction.status = 'TO_EXECUTE'
From anotherTable
JOIN anotherTable2 ON transaction.serviceId = anotherTable2.id
WHERE transaction.id = anotherTable.id AND transaction.status = :filter1, transaction.filter2 = :filter2, ...

Execute Dynamic Select into string in Teradata

This is the MySQL query, now I need this below dynamic query to execute in TERADATA SQL.
set l_sql=concat('SELECT max(',l_rid_col,'), MAX(cid) INTO #c2, #c3 FROM ',p_database,'.',p_table);
SET l_rid = #c2;
SET l_cid = #c3;
And this update query:
update table_a
set row = ifnull(l_rid, 0),
column = ifnull(l_cid, 0)
where databasename = p_database
and tablename = p_table;
But In Teradata I tried this way:
update table_a as a
from (select max(l_rid) TR, MAX(l_cid) TCC
from DEVP.employees) as b
set a.row = b.TR, a.column = b.TCC
where a.databasename = 'DEVP'
and a.tablename = 'employees';
Please remove the alias name from the LHS of the update statement.
a.colA=b.colname should be colA=b.colname
I got the answer:
update table_a from (select max(l_rid) TR, MAX(l_cid) TCC from DEVP.employees )as b
set row= b.TR , column=b.TCC where databasename='DEVP' and tablename='employees';
ISSUE: I just removed the alias name in UPDATE. finally got it.

Calling Stored Procedure on Column TSQL

Here is my situation. I know there must be a simple answer, but I am just not well versed in TSQL to know how. Below I have the main query of a stored procedure that selects the data I need. I have it working so far except that I need to call a seperate stored procedure called GetRecordMediaById where I feed it the Id from the PhotoId column, and it selects the BLOB data from the appropriate database which then needs to be its own column in the final query or replace the original PhotoId column.
I have no clue how to go about this. I've tried implementing temp tables, but I could never even get it to execute.
Here is my code:
ALTER PROCEDURE [dbo].[GetRollCallData]
#Ids VARCHAR(255),
#LexiconId INT,
#UUID UNIQUEIDENTIFIER,
#ReadOnly INT
AS
DECLARE #TableCode INT
SET #TableCode = 58
EXEC InsertInSelectionCache #Ids, #UUID, #TableCode, 0
WITH DOACTE AS(
SELECT ROW_NUMBER() OVER(PARTITION BY [File].Id ORDER BY CustomRecordsetId DESC) AS RowNumber, [File].*, FileType2Lexicon.Label as FileTypeLabel, [People].DefaultPhone, [People].InvertedName, CustomFieldValue.Value as DateofArrest
FROM FileType2Lexicon, SelectionCache, [People], [File]
INNER JOIN [CustomRecordSet]
ON [CustomRecordset].RecordId = [File].Id
INNER JOIN CustomFieldValue
ON [CustomRecordset].Id = CustomFieldValue.CustomRecordsetId
INNER JOIN [CustomField2Lexicon]
ON CustomField2Lexicon.CustomFieldId = CustomFieldValue.CustomFieldId
WHERE [File].Id = SelectionCache.RecordId
AND SelectionCache.UUID = #UUID
AND SelectionCache.TableCode = #TableCode -- this is the code for File table
AND [File].Id <> 0
AND [File].FileTypeId = FileType2Lexicon.FileTypeId
AND FileType2Lexicon.LexiconId = #LexiconId
AND [File].ClientIdString = [People].ClientIdString
AND CustomFieldValue.Value <> ''
AND CustomField2Lexicon.Label = 'Date of Arrest'),
PHOTOCTE AS(
SELECT [File].Id, CustomFieldValue.Value as PhotoId
FROM FileType2Lexicon, SelectionCache, [People], [File]
INNER JOIN [CustomRecordSet]
ON [CustomRecordset].RecordId = [File].Id
INNER JOIN CustomFieldValue
ON [CustomRecordset].Id = CustomFieldValue.CustomRecordsetId
INNER JOIN [CustomField2Lexicon]
ON CustomField2Lexicon.CustomFieldId = CustomFieldValue.CustomFieldId
WHERE [File].Id = SelectionCache.RecordId
AND SelectionCache.UUID = #UUID
AND SelectionCache.TableCode = #TableCode -- this is the code for File table
AND [File].Id <> 0
AND [File].FileTypeId = FileType2Lexicon.FileTypeId
AND FileType2Lexicon.LexiconId = #LexiconId
AND [File].ClientIdString = [People].ClientIdString
AND CustomFieldValue.Value <> ''
AND CustomField2Lexicon.Label = 'Booking Photo')
SELECT DOACTE.*, PHOTOCTE.PhotoId
FROM DOACTE
INNER JOIN
PHOTOCTE
ON DOACTE.Id = PHOTOCTE.Id
WHERE DOACTE.RowNumber = 1
EDIT:
Solution for me was to create a scalar function that resolves the Id in the BLOB database and returns the BLOB data.
SELECT DOACTE.*, dbo.GetImagebyId(PHOTOCTE.PhotoId) as Photo,
FROM DOACTE
INNER JOIN
PHOTOCTE
ON DOACTE.Id = PhotoCTE.Id
WHERE DOACTE.RowNumber = 1
You can declare a #table_variable and insert the results from "EXEC InsertInSelectionCache #Ids, #UUID, #TableCode, 0" into the table variable.
Then you can join to the #table_variable in the final query.
See here for examples: How to return temporary table from stored procedure

How to set a bit based on a value existing in a table

I have a table. I have 2 variables, one is a bit, the other is an int.
Table: WorkGroupCollectionDetail
Variables: #WorkgroupID int, #IsFSBP bit
The table has WorkGroupId int PK and WorkGroupCollectionCode varchar PK. That's it.
I can run a query like this:
SELECT WorkGroupId
FROM WorkGroupCollectionDetail
WHERE WorkGroupCollectionCode = 'FSBP'
and it gives me a list of WorkGroupID.
So what I need to do is if the value of #WorkgroupID is inside the results of that query, I need to set the bit variable to true.
select #IsFBSP = case
when exists (
select 42 from WorkGroupDetailCollection
where WorkGroupCollectionCode = 'FSBP' and WorkGroupId = #WorkGroupId ) then 1
else 0 end
which is logically equivalent to:
select #IsFBSP = case
when #WorkGroupId in (
select WorkGroupId from WorkGroupDetailCollection
where WorkGroupCollectionCode = 'FSBP' ) then 1
else 0 end
A query using EXISTS often performs better than a query using IN. You can check the execution plans to see how they compare in your particular case.
Note that these examples include setting the bit value to zero as well as one.
You could modify the SELECT to include the check for the WorkGroupId and update the #IsFSBP accordingly:
IF EXISTS(SELECT WorkGroupId
FROM WorkGroupCollectionDetail
WHERE WorkGroupCollectionCode = 'FSBP'
AND WorkGroupId = #WorkgroupID)
BEGIN
SELECT #IsFSBP = 1;
END
SQL Fiddle example
I'm guessing you're looking for
Set #BitVariable = count(*)
From TestTable
WHERE TestCode = 'TestValue' and TestID = #TestID