I worked on management studio in the past and remember explain/query plan was descriptive like it used to tell
1) Order in which statements will be fired
2) Number of rows return by each statement
I am using "explain plan" by OracleSQL developer but i don't see above features. Is there any other good free tool ?
Order in which statements will be fired
Adrian Billington has created an "XPlan Utility", to extend the output of DBMS_XPLAN to include the execution order of the steps. The following output shows the difference between the default output and that produced by Adrian's XPlan Utility.
For example,
EXPLAIN PLAN FOR
SELECT *
FROM emp e, dept d
WHERE e.deptno = d.deptno
AND e.ename = 'SMITH';
SET LINESIZE 130
-- Default Output
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 3625962092
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 58 | 3 (0)| 00:00:53 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 1 | 58 | 3 (0)| 00:00:53 |
|* 3 | TABLE ACCESS FULL | EMP | 1 | 38 | 2 (0)| 00:00:35 |
|* 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 20 | 1 (0)| 00:00:18 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("E"."ENAME"='SMITH')
4 - access("E"."DEPTNO"="D"."DEPTNO")
18 rows selected.
SQL>
Let's see the extended plan to see the order of steps. See the ORD column:
-- XPlan Utility output
#xplan.display.sql
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 3625962092
----------------------------------------------------------------------------------------------------
| Id | Pid | Ord | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------
| 0 | | 6 | SELECT STATEMENT | | 1 | 58 | 3 (0)| 00:00:53 |
| 1 | 0 | 5 | NESTED LOOPS | | | | | |
| 2 | 1 | 3 | NESTED LOOPS | | 1 | 58 | 3 (0)| 00:00:53 |
|* 3 | 2 | 1 | TABLE ACCESS FULL | EMP | 1 | 38 | 2 (0)| 00:00:35 |
|* 4 | 2 | 2 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 |
| 5 | 1 | 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 20 | 1 (0)| 00:00:18 |
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("E"."ENAME"='SMITH')
4 - access("E"."DEPTNO"="D"."DEPTNO")
About
------
- XPlan v1.2 by Adrian Billington (http://www.oracle-developer.net)
18 rows selected.
SQL>
Number of rows return by each statement
In SQL Developer, the explain plan window has the cardinality column which shows the number of rows.
In SQL*Plus, using DBMS_XPLAN, you can display in a readable format. The rows column shows the number of rows.
See How to create and display explain plan in SQL*Plus. Few good examples and usage here.
Related
I need a function which takes in an integer *n as input, and checks through a database table to return all the rows from the first to the nth row. The function should also be able to return the last n rows from the table.
In the table below, I have 10 rows on the table. If I want to get just the 'head' of the table, or the first 5 rows, I just have to pass 5 to the function and it should return the output I want.
This is similar to the df.head() method used in Pandas. The function should not take values equal to or higher than the total number of rows for the table.
I am using GridDB python client and I have created my Factory instance and stored my database table.
'''
-- | id | first_name | last_name | salary_$ |
-- |----|------------|------------|-----------|
-- | 1 | Josh | Mac | 175000 |
-- | 2 | Hong | Williams | 150000 |
-- | 3 | Ajay | Kumar | 125000 |
-- | 4 | Jay | Mac | 100000 |
-- | 5 | John | Jonah | 95000 |
-- | 6 | Lucy | Judas | 80000 |
-- | 7 | Matthew | Stones | 80000 |
-- | 8 | Kang | Choi | 70000 |
-- | 9 | Rajiv | Kumar | 50000 |
-- | 10 | Smith | Peters | 50000 |
'''
I am working on a project in which we should evaluate suppliers and in this database I have this table EvaluationGrade:
+------+---------------------+------------+-----------+
| Id | EvaluationMethodId | FromScore | ToScore |
+------+---------------------+------------+-----------+
| 1 | 2 | 1 | 20 |
| 2 | 2 | 21 | 50 |
| 3 | 2 | 51 | 70 |
| 4 | 2 | 71 | 100 |
| 5 | 3 | 1 | 20 |
| 6 | 3 | 31 | 40 |
+------+---------------------+------------+-----------+
This table categorize scores and I am gonna be sure for EvaluationMethodId=2 scope values fill 1 to 100 (just like sample above).
I am looking for something like this:
+---------------------+------------+
| EvaluationMethodId | Sum |
+---------------------+------------+
| 2 | 100 |
| 3 | 30 |
+---------------------+------------+
This is the way I attempted:
WITH myUpdate
AS (SELECT emg.Id,emg.EvaluationMethodId,
SUM(emg.ToGrade - emg.FromGrade) + 1 AS SumScope
FROM generalsup.EvaluationMethodGrading emg
GROUP BY emg.Id,emg.EvaluationMethodId)
SELECT myUpdate.EvaluationMethodId, SUM(myUpdate.SumScope) AS SumScopeAll
FROM myUpdate
GROUP BY myUpdate.EvaluationMethodId;
But I use window function that put less overhead on server.
Since there is no case of overlaps in the scores, you can do it with group by EvaluationMethodId and sum():
select EvaluationMethodId, sum(ToScore - FromScore + 1) [Sum]
from EvaluationMethodGrading
group by EvaluationMethodId
See the demo.
Results:
> EvaluationMethodId | Sum
> -----------------: | --:
> 2 | 100
> 3 | 30
Is it possible to sorting queries table in hierarchical order like this:
Expected
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| ID | Code | Name | Qty | Amount | is_parent | parent_id | remarks |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 1 | ABC | Parent1 | 2 | 1,000 | 1 | 0 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 4 | FFLK | Product Z | 10 | 2,500 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 5 | P6DT | Product 5 | 7 | 1,700 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 6 | P2GL | Product T | 5 | 1,100 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 2 | DHG | Parent2 | 5 | 1,500 | 1 | 0 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 3 | LMSJ | Product U | 4 | 600 | 0 | 2 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
This is the original data table:
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| ID | Code | Name | Qty | Amount | is_parent | parent_id | remarks |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 1 | ABC | Parent1 | 2 | 1,000 | 1 | 0 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 2 | DHG | Parent2 | 5 | 1,500 | 1 | 0 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 3 | LMSJ | Product U | 4 | 600 | 0 | 2 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 4 | FFLK | Product Z | 10 | 2,500 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 5 | P6DT | Product 5 | 7 | 1,700 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
| 6 | P2GL | Product T | 5 | 1,100 | 0 | 1 | xxx |
+----+--------+-----------+-------+--------+-----------+-----------+---------+
is_parent column = 1 if data row set to parent, 0 if data row set to child
parent_id column = 0 if data row set to parent, depend on ID of parent data
I'm using SQL Server to generate the data.
It looks like the actual question is how to query the data in hierarchical order. This is possible using recursive queries but a faster alternative is to use SQL Server's support for hierarchical data.
A recursive query that returns the data in hierarchical order would look like this :
WITH h AS
(
SELECT
ID,Code,Name,Qty,Amount,is_parent,parent_id,remarks
FROM
dbo.ThatTable
WHERE
parent_id=0
UNION ALL
SELECT
c.ID,c.Code,c.Name,c.Qty,c.Amount,c.is_parent,c.parent_id,c.remarks
FROM
dbo.ThatTable c
INNER JOIN h ON
c.parent_id= h.Id
)
SELECT * FROM h
This query's performance will be acceptable if the ID and Parent_ID fields are indexed, but not great.
Adding a hierarchyid field to the table would make the query simpler and far faster. Assuming there's a hierarchy field, the query would be just :
SELECT *
FROM ThatTable
ORDER BY hierarchy
Adding an index on hierarchy will this query and any query that looks eg for children of a specific node, very fast. Instead of querying recursively, the server only needs to look into that single index.
The article Lesson 1: Converting a Table to a Hierarchical Structure shows how to create a new table with a hierarchyid and populate it from parent/child data.
When I get the execution plan of the query below, even if I write right outer join, it writes left outer join.
select * from employees e right outer join departments d
using(department_id);
And this is the output:
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 122 | 10980 | 6 (17)| 00:00:01 |
| 1 | MERGE JOIN OUTER | | 122 | 10980 | 6 (17)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 27 | 567 | 2 (0)| 00:00:01 |
| 3 | INDEX FULL SCAN | DEPT_ID_PK | 27 | | 1 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 107 | 7383 | 4 (25)| 00:00:01 |
| 5 | TABLE ACCESS FULL | EMPLOYEES | 107 | 7383 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID"(+))
filter("D"."DEPARTMENT_ID"="E"."DEPARTMENT_ID"(+))
If I use the left outer join, this time it shows right outer join. What is the reason of that?
select * from employees e left outer join departments d using(department_id);
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 107 | 9630 | 6 (0)| 00:00:01 |
|* 1 | HASH JOIN RIGHT OUTER| | 107 | 9630 | 6 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | DEPARTMENTS | 27 | 567 | 3 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL | EMPLOYEES | 107 | 7383 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID"(+))
Thanks in advance.
I have three tables:
My products with their IDs and their features.
is a table with treatments of my products with a treatment-ID, a method, and a date. The treatments are done in batches of many products so there is a crosstable
with the products IDs and the treatment IDs and a bool value for the success of the treatment.
Each product can undergo many different treatments so there is a many-to-many relation. I now want to add to the product table (1.) for every product a value that shows the method of its most recent successful treatment if there is any.
I made a query that groups the crosstable's entries by product-ID but I don't know how to show the method and date of it's last treatment.
table 1:
| productID | size | weight | height | ... |
|-----------|:----:|-------:|--------|-----|
| 1 | 13 | 16 | 9 | ... |
| 2 | 12 | 17 | 12 | ... |
| 3 | 11 | 15 | 15 | ... |
| ... | ... | ... | ... | ... |
table 2:
| treatmentID | method | date |
|-------------|:--------:|-----------:|
| 1 | dye blue | 01.02.2016 |
| 2 | dye red | 01.02.2017 |
| 3 | dye blue | 01.02.2018 |
| ... | ... | ... |
table 3:
| productID | treatmentID | success |
|-----------|:-----------:|--------:|
| 1 | 1 | yes |
| 1 | 2 | yes |
| 1 | 3 | no |
| ... | ... | ... |
I need table 1 to be like:
table 1:
| productID | size | weight | height | latest succesful method |
|-----------|:----:|-------:|--------|-------------------------|
| 1 | 13 | 16 | 9 | dye red |
| 2 | 12 | 17 | 12 | ... |
| 3 | 11 | 15 | 15 | ... |
| ... | ... | ... | ... | ... |
My query:
SELECT table3.productID, table2.method
FROM table2 INNER JOIN table3 ON table2.treatmentID = table3.treatmentID
GROUP BY table3.productID, table2.method
HAVING (((table3.productID)=Max([table2].[date])))
ORDER BY table3.productID DESC;
but this does NOT show only one (the most recent) entry but all of them.
Simplest solution here would be to write either a subquery within your sql, or create a new query to act as a subquery(it will look like a table) to help indicate(or elminate) the records you want to see.
Using similar but potentially slightly different source data as you only gave one example.
Table1
| ProductID | Size | Weight | Height |
|-----------|------|--------|--------|
| 1 | 13 | 16 | 9 |
| 2 | 12 | 17 | 12 |
| 3 | 11 | 15 | 15 |
Table2
| TreatmentID | Method | Date |
|-------------|------------|----------|
| 1 | dye blue | 1/2/2016 |
| 2 | dye red | 1/2/2017 |
| 3 | dye blue | 1/2/2018 |
| 4 | dye yellow | 1/4/2017 |
| 5 | dye brown | 1/5/2018 |
Table3
| ProductID | TreatmentID | Success |
|-----------|-------------|---------|
| 1 | 1 | yes |
| 1 | 2 | yes |
| 1 | 3 | no |
| 2 | 4 | no |
| 2 | 5 | yes |
First order of business is to get the max(dates) and productIds of successful treatments.
We'll do this by aggregating the date along with the productIDs and "success".
SELECT Table3.productid, Max(Table2.Date) AS MaxOfdate, Table3.success
FROM Table2 INNER JOIN Table3 ON Table2.treatmentid = Table3.treatmentid
GROUP BY Table3.productid, Table3.success;
This should give us something along the lines of:
| ProductID | MaxofDate | Success |
|-----------|-----------|---------|
| 1 | 1/2/2018 | No |
| 1 | 1/2/2017 | Yes |
| 2 | 1/4/2017 | No |
| 2 | 1/8/2017 | Yes |
We'll save this query as a "regular" query. I named mine "max", you should probably use something more descriptive. You'll see "max" in this next query.
Next we'll join tables1-3 together but in addition we will also use this "max" subquery to link tables 1 and 2 by the productID and MaxOfDate to TreatmentDate where success = "yes" to find the details of the most recent SUCCESSFUL treatment.
SELECT table1.productid, table1.size, table1.weight, table1.height, Table2.method
FROM ((table1 INNER JOIN [max] ON table1.productid = max.productid)
INNER JOIN Table2 ON max.MaxOfdate = Table2.date) INNER JOIN Table3 ON
(Table2.treatmentid = Table3.treatmentid) AND (table1.productid = Table3.productid)
WHERE (((max.success)="yes"));
The design will look something like this:
Design
(ps. you can add queries to your design query editor by clicking on the "Queries" tab when you are adding tables to your query design. They act just like tables, just be careful as very detailed queries tend to bog down Access)
Running this query should give us our final results.
| ProductID | Size | Weight | Height | Method |
|-----------|------|--------|--------|-----------|
| 1 | 13 | 16 | 9 | dye red |
| 2 | 12 | 17 | 12 | dye brown |