### 27.19.2 Obtaining Parent Event Information

[]()[]()[]()[]()

 The [`data_locks`](performance-schema-data-locks-table.html) table shows data locks held and requested. Rows of this table have a `THREAD_ID` column indicating the thread ID of the session that owns the lock, and an `EVENT_ID` column indicating the Performance Schema event that caused the lock. Tuples of (`THREAD_ID`, `EVENT_ID`) values implicitly identify a parent event in other Performance Schema tables:

* The parent wait event in the `events_waits_*`xxx`*` tables

* The parent stage event in the `events_stages_*`xxx`*` tables

* The parent statement event in the `events_statements_*`xxx`*` tables

* The parent transaction event in the [`events_transactions_current`](performance-schema-events-transactions-current-table.html) table

 To obtain details about the parent event, join the `THREAD_ID` and `EVENT_ID` columns with the columns of like name in the appropriate parent event table. The relation is based on a nested set data model, so the join has several clauses. Given parent and child tables represented by `parent` and `child`, respectively, the join looks like this:

```
WHERE
  parent.THREAD_ID = child.THREAD_ID        /* 1 */
  AND parent.EVENT_ID < child.EVENT_ID      /* 2 */
  AND (
    child.EVENT_ID <= parent.END_EVENT_ID   /* 3a */
    OR parent.END_EVENT_ID IS NULL          /* 3b */
  )
```

 The condititions for the join are:

1. The parent and child events are in the same thread.

2. The child event begins after the parent event, so its `EVENT_ID` value is greater than that of the parent.

3. The parent event has either completed or is still running.

 To find lock information, [`data_locks`](performance-schema-data-locks-table.html) is the table containing child events.

 The [`data_locks`](performance-schema-data-locks-table.html) table shows only existing locks, so these considerations apply regarding which table contains the parent event:

* For transactions, the only choice is [`events_transactions_current`](performance-schema-events-transactions-current-table.html). If a transaction is completed, it may be in the transaction history tables, but the locks are gone already.

* For statements, it all depends on whether the statement that took a lock is a statement in a transaction that has already completed (use [`events_statements_history`](performance-schema-events-statements-history-table.html)) or the statement is still running (use [`events_statements_current`](performance-schema-events-statements-current-table.html)).

* For stages, the logic is similar to that for statements; use [`events_stages_history`](performance-schema-events-stages-history-table.html) or [`events_stages_current`](performance-schema-events-stages-current-table.html).

* For waits, the logic is similar to that for statements; use [`events_waits_history`](performance-schema-events-waits-history-table.html) or [`events_waits_current`](performance-schema-events-waits-current-table.html). However, so many waits are recorded that the wait that caused a lock is most likely gone from the history tables already.

 Wait, stage, and statement events disappear quickly from the history. If a statement that executed a long time ago took a lock but is in a still-open transaction, it might not be possible to find the statement, but it is possible to find the transaction.

 This is why the nested set data model works better for locating parent events. Following links in a parent/child relationship (data lock -\> parent wait -\> parent stage -\> parent transaction) does not work well when intermediate nodes are already gone from the history tables.

 The following scenario illustrates how to find the parent transaction of a statement in which a lock was taken:

 Session A:

```
[1] START TRANSACTION;
[2] SELECT * FROM t1 WHERE pk = 1;
[3] SELECT 'Hello, world';
```

 Session B:

```
SELECT ...
FROM performance_schema.events_transactions_current AS parent
  INNER JOIN performance_schema.data_locks AS child
WHERE
  parent.THREAD_ID = child.THREAD_ID
  AND parent.EVENT_ID < child.EVENT_ID
  AND (
    child.EVENT_ID <= parent.END_EVENT_ID
    OR parent.END_EVENT_ID IS NULL
  );
```

 The query for session B should show statement [2] as owning a data lock on the record with `pk=1`.

 If session A executes more statements, [2] fades out of the history table.

 The query should show the transaction that started in [1], regardless of how many statements, stages, or waits were executed.

 To see more data, you can also use the `events_*`xxx`*_history_long` tables, except for transactions, assuming no other query runs in the server (so that history is preserved).

