Adding locks for serializability - serialization

I am trying to enforce serializability for the following transaction schedule but my solution schedule seems to contain a logical error somewhere.
T1: W(Y)
T2: R(V) R(Y) W(Z)
T3: W(V)
I would add the following S- and X-locks:
T1: X(Y) W(Y) U(Y)
T2: S(V) R(V) S(Y) R(Y) W(Z) U(Y) U(V)
T3: X(V) W(V) U(V)
So the W(Y) / R(Y) and W(V) / R(V) definitely need to be locked. W(Z) does not have to. But for some reason the schedule reasoner returns a logical error.
Can anyone tell me whether I have made a mistake?

This solution may be helpful:
T1: X(Y) W(Y) U(Y)
T2: S(V) R(V) S(Y) U(V) R(Y) U(Y) W(Z)
T3: X(V) W(V) U(V)

Related

Transfer Access Code into Oracle Syntax (Power Query)

I am just woorking on to transfer a Access Query into Power Query (Excel).
I think there are some challenges regarding the terms/ wording.
Its a Oracle DB.
The original code looks like this one:
SELECT
POOLK.DATA.DOC,
Val(Min(Right([PNR],5))) AS Value,
POOLK.DATA.RE,
POOLK.DATA.ST INTO [tValue]
FROM
POOLK.DATA
GROUP BY
POOLK.DATA.DOC,
POOLK.DATA.RE,
POOLK.DATA.ST
HAVING (((POOLK.DATA.DOC)>25000) AND ((POOLK.DATA.RE)="B9"))
ORDER BY POOLK.DATA.DOC DESC
This is my approach since now:
SELECT
LTRIM((SUBSTR(POOLK.DATA."PNR", -5)), '0') AS Value,
POOLK.DATA.DOC,
POOLK.DATA.RE,
POOLK.DATA.ST
FROM
POOLK.DATA
WHERE
POOLK.DATA.DOC >25000
AND
POOLK.DATA.RE ='B9'
I get failures with the HAVING and GROUP BY functions.
I think where presents other value, right?
Have someone ideas?
Best Regards
You still need the GROUP BY:
SELECT LTRIM(MIN(SUBSTR(D.PNR, -5)), '0') AS Value,
D.DOC, D.RE, D.ST
FROM POOLK.DATA d
WHERE D.DOC > 25000 AND
D.RE ='B9'
GROUP BY D.DOC, D.RE, D.ST;
I also added table aliases so the code is easier to write and to read.
The INTO is creating a table. If you really want to do that then:
create table tvalue as
SELECT LTRIM(MIN(SUBSTR(D.PNR, -5)), '0') AS Value,
D.DOC, D.RE, D.ST
FROM POOLK.DATA d
WHERE D.DOC > 25000 AND
D.RE ='B9'
GROUP BY D.DOC, D.RE, D.ST;

How to join multiple tables and find pairs

We are currently studying for a lecture about databases and we are not sure if our solution is the right way to solve this kind of problem.
The following scheme is given:
Translation of the relevant relations:
Lecture(LectureID[PK], LectureTitle, ProfInitials)
VG(LectureID[PK, FK1], SubjectTitle[PK, FK2]
Subject(Titel[PK], Description)
The task is to find pairs of lectures ("Vorlesung") that have a subject ("Gebiet") in common. The resulting table should contain the names of both lectures ("VTitel") and the titel of the shared subject ("Titel").
The soulution we came up with is
SELECT "T1"."VTitel", "T2"."VTitel", "T1"."Titel"
FROM (SELECT v1."VTitel", "Titel" FROM "Vorlesung" v1 NATURAL JOIN "VG" g) AS "T1"
JOIN (SELECT v1."VTitel", "Titel" FROM "Vorlesung" v1 NATURAL JOIN "VG" g) AS "T2"
ON "T1"."Titel" = "T2"."Titel" AND "T1"."VTitel" <> "T2"."VTitel";
Is this the right way to solve this or is there a much easier way to do this?
That looks like it will give you the correct answer, however in practice it is usually faster (and often, though not always more readable), to avoid nested sub-queries. I assume you've had some lectures on relational algebra, so you'll notice that if you translate your query into relational form it turns out to be rather long (I renamed your tables and columns and used this site to generate it, but you should do it yourself by hand; S is Vorlesung and T is VG, b and d are the two fields in each table):
π T1.b, T2.b, T1.d ρ T1 ( π v1.b, v1.d ρ v1 S ⨝ ρ g T) ⨝ T1.d = T2.d and T1.b ≠ T2.b ρ T2 ( π v1.b, v1.d ρ v1 S ⨝ ρ g T)
This uses 12 operators. Instead of having selects inside your joins, maybe you want to simply rename all instances of your tables to different names and join them all together!
SELECT V1.VTitel,
V2.VTitel,
VG1.Titel
FROM Vorlesung AS V1
JOIN VG AS VG1
ON VG1.VNummer = V1.VNummer
JOIN Vorlesung AS V2
ON V1.VTitel <> V2.VTitel
JOIN VG AS VG2
ON VG2.VNummer = V2.VNummer
WHERE VG2.Titel = VG1.Titel
This gives us a more manageable 9 operators:
π V1.b, V2.b, V1.d σ VG1.b = VG2.b ρ V1 S ⨝ VG1.d = V1.d ρ VG1 T ⨝ V1.b ≠ V2.b ρ V2 S ⨝ VG2.d = V2.d ρ VG2 T
Note I've gotten rid of the natural joins so that we don't have to worry about brackets and such; natural joins are also a terrible thing to use in real life, but make sense in theory. It's a good exercise to see if you understand what I did if you can rewrite the new query with natural joins, and if you can write it again without a where clause!

How to detect query which holds the lock in Postgres?

I want to track mutual locks in postgres constantly.
I came across Locks Monitoring article and tried to run the following query:
SELECT bl.pid AS blocked_pid,
a.usename AS blocked_user,
kl.pid AS blocking_pid,
ka.usename AS blocking_user,
a.query AS blocked_statement
FROM pg_catalog.pg_locks bl
JOIN pg_catalog.pg_stat_activity a ON a.pid = bl.pid
JOIN pg_catalog.pg_locks kl ON kl.transactionid = bl.transactionid AND kl.pid != bl.pid
JOIN pg_catalog.pg_stat_activity ka ON ka.pid = kl.pid
WHERE NOT bl.granted;
Unfortunately, it never returns non-empty result set. If I simplify given query to the following form:
SELECT bl.pid AS blocked_pid,
a.usename AS blocked_user,
a.query AS blocked_statement
FROM pg_catalog.pg_locks bl
JOIN pg_catalog.pg_stat_activity a ON a.pid = bl.pid
WHERE NOT bl.granted;
then it returns queries which are waiting to acquire a lock. But I cannot manage to change it so that it can return both blocked and blocker queries.
Any ideas?
Since 9.6 this is a lot easier as it introduced the function pg_blocking_pids() to find the sessions that are blocking another session.
So you can use something like this:
select pid,
usename,
pg_blocking_pids(pid) as blocked_by,
query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
From this excellent article on query locks in Postgres, one can get blocked query and blocker query and their information from the following query.
CREATE VIEW lock_monitor AS(
SELECT
COALESCE(blockingl.relation::regclass::text,blockingl.locktype) as locked_item,
now() - blockeda.query_start AS waiting_duration, blockeda.pid AS blocked_pid,
blockeda.query as blocked_query, blockedl.mode as blocked_mode,
blockinga.pid AS blocking_pid, blockinga.query as blocking_query,
blockingl.mode as blocking_mode
FROM pg_catalog.pg_locks blockedl
JOIN pg_stat_activity blockeda ON blockedl.pid = blockeda.pid
JOIN pg_catalog.pg_locks blockingl ON(
( (blockingl.transactionid=blockedl.transactionid) OR
(blockingl.relation=blockedl.relation AND blockingl.locktype=blockedl.locktype)
) AND blockedl.pid != blockingl.pid)
JOIN pg_stat_activity blockinga ON blockingl.pid = blockinga.pid
AND blockinga.datid = blockeda.datid
WHERE NOT blockedl.granted
AND blockinga.datname = current_database()
);
SELECT * from lock_monitor;
As the query is long but useful, the article author has created a view for it to simplify it's usage.
This modification of a_horse_with_no_name's answer will give you the last (or current, if it's still actively running) query of the blocking session in addition to just the blocked sessions:
SELECT
activity.pid,
activity.usename,
activity.query,
blocking.pid AS blocking_id,
blocking.query AS blocking_query
FROM pg_stat_activity AS activity
JOIN pg_stat_activity AS blocking ON blocking.pid = ANY(pg_blocking_pids(activity.pid));
This helps you understand which operations are interfering with each other (even if the block comes from a previous query), helping you understand the impact of killing one session and figuring out how to prevent blocking in the future.
Postgres has a very rich system catalog exposed via SQL tables.
PG's statistics collector is a subsystem that supports collection and reporting of information about server activity.
Now to figure out the blocking PIDs you can simply query pg_stat_activity.
select pg_blocking_pids(pid) as blocked_by
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
To, get the query corresponding to the blocking PID, you can self-join or use it as a where clause in a subquery.
SELECT query
FROM pg_stat_activity
WHERE pid IN (select unnest(pg_blocking_pids(pid)) as blocked_by from pg_stat_activity where cardinality(pg_blocking_pids(pid)) > 0);
Note: Since pg_blocking_pids(pid) returns an Integer[], so you need to unnest it before you use it in a WHERE pid IN clause.
Hunting for slow queries can be tedious sometimes, so have patience. Happy hunting.
How to show all blocked queries.
select pid,
usename,
pg_blocking_pids(pid) as blocked_by,
query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0;
You can kill a blocked query by using the below command.
SELECT pg_cancel_backend(a.pid), pg_terminate_backend(a.pid);
You can terminate all blocked queries using it.
SELECT pg_cancel_backend(a.pid), pg_terminate_backend(a.pid)
FROM( select pid,
usename,
pg_blocking_pids(pid) as blocked_by,
query as blocked_query
from pg_stat_activity
where cardinality(pg_blocking_pids(pid)) > 0) a
for postgresql versions earlier than postgresql 9.6 which does not have pg_blocking_pids function,you can use following query to find blocked query and blocking query.
SELECT w.query AS waiting_query,
w.pid AS waiting_pid,
w.usename AS waiting_user,
now() - w.query_start AS waiting_duration,
l.query AS locking_query,
l.pid AS locking_pid,
l.usename AS locking_user,
t.schemaname || '.' || t.relname AS tablename,
now() - l.query_start AS locking_duration
FROM pg_stat_activity w
JOIN pg_locks l1 ON w.pid = l1.pid AND NOT l1.granted
JOIN pg_locks l2 ON l1.relation = l2.relation AND l2.granted
JOIN pg_stat_activity l ON l2.pid = l.pid
JOIN pg_stat_user_tables t ON l1.relation = t.relid
WHERE w.waiting;
One thing I find that is often missing from these is an ability to look up row locks. At least on the larger databases I have worked on, row locks are not shown in pg_locks (if they were, pg_locks would be much, much larger and there isn't a real data type to show the locked row in that view properly).
I don't know that there is a simple solution to this but usually what I do is look at the table where the lock is waiting and search for rows where the xmax is less than the transaction id present there. That usually gives me a place to start, but it is a bit hands-on and not automation friendly.
Note that shows you uncommitted writes on rows on those tables. Once committed, the rows are not visible in the current snapshot. But for large tables, that is a pain.
Others have already answered your query, but I had certain situation: There were lots of queries blocking each other and I wanted to find the main blocker sessions for each blocked session.
Fir example session 5 was blocked by session 4 and 4 was waitig for 3 and 2 while 3 and 2 were waiting for session 1.
5->4->{3,2}->1
In this case session 1 is real problem, once it is cleared, others will take care of themselves.
So I wanted a query which will show me results like this:
Blocked pid
Blocker pid
5
1
4
1
3
1
2
1
So if there is any chain locked sessions, this query will show you the main blocker sessions for each blocked session.
;with recursive
find_the_source_blocker as (
select pid
,pid as blocker_id
from pg_stat_activity pa
where pa.state<>'idle'
and array_length(pg_blocking_pids(pa.pid), 1) is null
union all
select
t.pid as pid
,f.blocker_id as blocker_id
from find_the_source_blocker f
join ( SELECT
act.pid,
blc.pid AS blocker_id
FROM pg_stat_activity AS act
LEFT JOIN pg_stat_activity AS blc ON blc.pid = ANY(pg_blocking_pids(act.pid))
where act.state<>'idle') t on f.pid=t.blocker_id
)
select distinct
s.pid
,s.blocker_id
,pb.usename as blocker_user
,pb.query_start as blocker_start
,pb.query as blocker_query
,pt.query_start as trans_start
,pt.query as trans_query
from find_the_source_blocker s
join pg_stat_activity pb on s.blocker_id=pb.pid
join pg_stat_activity pt on s.pid=pt.pid
where s.pid<>s.blocker_id

Improved way for multi-table SQL (MySQL) query?

Hoping you can help. I have three tables and would like to create a conditional query to make a subset based on a row's presence in one table then excluding the row from the results, then query a final, 3rd table. I thought this would be simple enough, but I'm not well practiced in SQL and after researching/testing for 6 hours on left joins, correlated sub-queries etc, it has helped, but I still can't hit the correct result set. So here's the setup:
T1
arn_mkt_stn
A00001_177_JOHN_FM
A00001_177_BILL_FM
A00001_174_DAVE_FM
A00002_177_JOHN_FM
A00006_177_BILL_FM
A00010_177_JOHN_FM - note: the name's relationship to the 3 digit prefix (e.g. _177) and the FM part always is consistent: '_177_JOHN_FM' only the A000XX changes
T2
arn_mkt
A00001_105
A00001_177
A00001_188
A00001_246
A00002_177
A00003_177
A00004_026
A00004_135
A00004_177
A00006_177
A00010_177
Example: So if _177_JOHN_FM is a substring of arn_mkt_stn rows in T1, exclude it when getting arn_mkts with a substring of 177 from T2 - in this case, the desired result set would be:
A00003_177
A00004_177
A00006_177
Similarly, _177_BILL_FM would return:
A00002_177
A00003_177
A00004_177
A00010_177
Then I would like to use this result set to pull records from a third table based on the 'A00003' etc
T3
arn
A00001
A00002
A00003
A00004
A00005
A00006
...
I've tried a number of methods [where here $stn_code = JOHN_FM and $stn_mkt = 177]
"SELECT * FROM T2, T1 WHERE arn != SUBSTRING(T1.arn_mkt_stn, 1,6)
AND SUBSTRING(T1.arn_mkt_stn, 12,7) = '$stn_code'
AND SUBSTRING(arn_mkt, 8,3) = '$stn_mkt' (then use this result to query T3..)
Also a left join and a subquery, but I'm clearly missing something!
Any pointers gratefully received, thanks,
Rich.
[EDIT: Thanks for helping out sgeddes. I'll expand on my logic above... first, the result set desired is always in connection with one name only per query, e.g. from T1, lets use JOHN_FM. In T1, JOHN_FM is currently associated with 'arn's (within the arn_mkt_stn): A00001, A00002 & A00010'. The next step in T2 is to find all the 'arn's (within arn_mkt)' that have JOHN_FM's 3 digit prefix (177), then exclude those that are in T1. Note: A00006 remains because it is not connected to JOHN_FM in T1. The same query for BILL_FM gives slightly different results, excluding A00001 & A00006 as it has this assoc in T1.. Thanks, R]
You can use a LEFT JOIN to remove the records from T2 that match those in T1. However, I'm not sure I'm understanding your logic.
You say A00001_177_JOHN_FM should return:
A00003_177
A00004_177
A00006_177
However, wouldn't A00006_177_BILL_FM exclude A00006_177 from the above results?
This query should be close (wasn't completely sure which fields you needed returned) to what you're looking for if I'm understanding you correctly:
SELECT T2.arn_mkt, T3.arn
FROM T2
LEFT JOIN T1 ON
T1.arn_mkt_stn LIKE CONCAT(T2.arn_mkt,'%')
INNER JOIN T3 ON
T2.arn_mkt LIKE CONCAT(T3.arn,'%')
WHERE T1.arn_mkt_stn IS NULL
Sample Fiddle Demo
--EDIT--
Reviewing the comments, this should be what you're looking for:
SELECT *
FROM T2
LEFT JOIN T1 ON
T1.arn_mkt_stn LIKE CONCAT(LEFT(T2.arn_mkt,LOCATE('_',T2.arn_mkt)),'%') AND T1.arn_mkt_stn LIKE '%JOHN_FM'
INNER JOIN T3 ON
T2.arn_mkt LIKE CONCAT(T3.arn,'%')
WHERE T1.arn_mkt_stn IS NULL
And here is the updated Fiddle: http://sqlfiddle.com/#!2/3c293/13

Query running slow after adding criteria

With much help from others I have this sql statement that calculates the difference in mileage (+ or -) between records in my table. Problem is that when I add a criteria (>0) to the the calculated value it dramatically slows my query. If I add a criteria to any other field then things run as expected (no long delay).
SELECT T1.Date,
T1.Route,
T1.BookingID,
T1.StreetNumber,
T1.Street,
T1.Arrive,
T1.Perform,
T1.Miles,
T1.Miles - (SELECT Miles
FROM Test1 AS T2
WHERE T2.Route = T1.Route
AND T2.IDNumber = (SELECT Min(IDNumber)
FROM Test1 AS T3
WHERE T3.Route = T1.Route
AND T3.IDNumber >
T1.IDNumber)) AS
Difference
FROM Test1 AS T1
GROUP BY T1.Date,
T1.Route,
T1.BookingID,
T1.StreetNumber,
T1.Street,
T1.Arrive,
T1.Perform,
T1.Miles,
T1.IdNumber,
T1.Status,
T1.Activityy
HAVING (( ( [T1].[Miles] - (SELECT Miles
FROM Test1 AS T2
WHERE T2.Route = T1.Route
AND T2.IDNumber = (SELECT Min(IDNumber)
FROM Test1 AS T3
WHERE T3.Route = T1.Route
AND T3.IDNumber >
T1.IDNumber)) ) > 0 ))
ORDER BY T1.IdNumber;
Your difference is just finding the next record with miles.
If you database supports row_number() or lag(), then you can rewrite this query using windows functions rather than multiple self-joins. That should fix the performance problem.
Otherwise, rewrite the query so the joins are in the "from" clause. That should also fix the problem.
Finally, if you want to use a temporary table, put all the results in a temporary table and do the selection afterwards. (This is not my preferred approach, but for a one-time query it might be the fastest solution.)