Pages

Search This Blog

Showing posts with label query. Show all posts
Showing posts with label query. Show all posts

Thursday, January 12, 2012

[Oracle] How to optimize queries - for Beginners

D.1 Optimizing Single-Table Queries

To improve the performance of a query that selects rows of a table based on a specific column value, create an index on that column. For example, the following query performs better if the NAME column of the EMP table has an index.
SELECT * 
FROM EMP 
WHERE NAME = 'Smith'; 

D.2 Optimizing Join Queries

The following can improve the performance of a join query (a query with more than one table reference in the FROM clause).

D.2.1 Create an Index on the Join Column(s) of the Inner Table

In the following example, the inner table of the join query is DEPT and the join column of DEPT is DEPT#. An index on DEPT.DEPT# improves the performance of the query. In this example, since DEPT# is the primary key of DEPT, an index is implicitly created for it. The optimizer will detect the presence of the index and decide to use DEPT as the inner table. In case there is also an index on EMP.WORKS_IN column the optimizer evaluates the cost of both orders of execution;DEPT followed by EMP (where EMP is the inner table) and EMP followed by DEPT (where DEPT is the inner table) and picks the least expensive execution plan.
SELECT e.SS#, e.NAME, d.BUDGET
FROM EMP e, DEPT d 
WHERE e.WORKS_IN = DEPT.DEPT# 
AND e.JOB_TITLE = 'Manager'; 

D.2.2 Bypassing the Query Optimizer

Normally optimizer picks the best execution plan, an optimal order of tables to be joined. In case the optimizer is not producing a good execution plan you can control the order of execution using the HINTS feature SQL. For more information see the Oracle9i Lite SQL Reference.
For example, if you want to select the name of each department along with the name of its manager, you can write the query in one of two ways. In the first example which follows, the hint /++ordered++/ says to do the join in the order the tables appear in the FROM clause with attempting to optimize the join order.
SELECT /++ordered++/ d.NAME, e.NAME
FROM DEPT d, EMP e
WHERE d.MGR = e.SS# 
or: 
SELECT /++ordered++/ d.NAME, e.NAME 
FROM EMP e, DEPT d 
WHERE d.MGR = e.SS# 
Suppose that there are 10 departments and 1000 employees, and that the inner  table in each query has an index on the join column. In the first query, the  first table produces 10 qualifying rows (in this case, the whole table). In the  second query, the first table produces 1000 qualifying rows. The first query  will access the EMP table 10 times and scan the DEPT table once. The second  query will scan the EMP table once but will access the DEPT table 1000 times.  Therefore the first query will perform much better. As a rule of thumb, tables  should be arranged from smallest effective number rows to largest effective  number of rows. The effective row size of a table in a query is obtained by  applying the logical conditions that are resolved entirely on that table. 
In another example, consider a query to retrieve the social security numbers and names of employees in a given location, such as New York. According to the sample schema, the query would have three table references in the FROM clause. The three tables could be ordered in six different ways. Although the result is the same regardless of which order you choose, the performance could be quite different.
Suppose the effective row size of the LOCATION table is small, for example select count(*) from LOCATION where LOC_NAME = 'New York' is a small set. Based on the above rules, the LOCATION table should be the first table in the FROM clause. There should be an index on LOCATION.LOC_NAME. Since LOCATION must be joined with DEPT, DEPT should be the second table and there should be an index on the LOC column of DEPT. Similarly, the third table should be EMP and there should be an index on EMP#. You could write this query as:
SELECT /++ordered++/ e.SS#, e.NAME 
FROM LOCATION l, DEPT d, EMP e 
WHERE l.LOC_NAME = 'New York' AND 
l.LOC# = d.LOC AND 
d.DEPT# = e.WORKS_IN;

D.3 Optimizing with Order By and Group By Clauses

Various performance improvements have been made so that SELECT statements run faster and consume less memory cache. Group by and Order by clauses attempt to avoid sorting if a suitable index is available.

D.3.1 IN subquery conversion

Converts IN subquery to a join when the select list in the subquery is uniquely indexed.
For example, the following IN subquery statement is converted to its corresponding join statement. This assumes that c1 is the primary key of table t2:
SELECT c2 FROM t1 WHERE 
c2 IN (SELECT c1 FROM t2);

becomes:
SELECT c2 FROM t1, t2 WHERE t1.c2 = t2.c1;

D.3.2 ORDER BY optimization with no GROUP BY

This eliminates the sorting step for an ORDER BY clause in a select statement if ALL of the following conditions are met:
  1. All ORDER BY columns are in ascending order or in descending order.
  2. Only columns appear in the ORDER BY clause. That is, no expressions are used in the ORDER BY clause.
  3. ORDER BY columns are a prefix of some base table index.
  4. The cost of accessing by the index is less than sorting the result set.

D.3.3 GROUP BY optimization with no ORDER BY

This eliminates the sorting step for the grouping operation if GROUP BY columns are the prefix of some base table index.

D.3.4 ORDER BY optimization with GROUP BY

When ORDER BY columns are the prefix of GROUP BY columns, and all columns are sorted in either ascending or in descending order, the sorting step for the query result is eliminated. If GROUP BY columns are the prefix of a base table index, the sorting step in the grouping operation is also eliminated.

D.3.5 Cache subquery results

If the optimizer determines that the number of rows returned by a subquery is small and the query is non-correlated, then the query result will be cached in memory for better performance. Currently the number of rows is set at 2000. For example:
select * from t1 where 
t1.c1 = (select sum(salary) 
from t2 where t2.deptno = 100);

Tuesday, November 29, 2011

[Oracle] How to see last sql statements executed

Recently we get into scenario where we need to see that which sql statements are being executed by activity upload.


So here is an easy way to do this:


select sql_text from v$sql where rownum<=100 and parsing_schema_name='NC_SDA_1_301';


Parsing Schema Name ; should be your schema name for which you need to see the sql statements executed on.

Tuesday, September 20, 2011

[Oracle] Update Data in Table trough Joins

create table source_table

(source_id    number primary key

,s_col1       number

,s_col2       number

,s_col3       number

);



create table target_table

(target_id    number primary key

,t_col1       number

,t_col2       number

,t_col3       number

);



insert into source_table(source_id,s_col1,s_col2,s_col3) values (101,111,1.01,-1);

insert into source_table(source_id,s_col1,s_col2,s_col3) values (102,222,2.02,-2);

insert into source_table(source_id,s_col1,s_col2,s_col3) values (103,333,3.03,-3);

insert into source_table(source_id,s_col1,s_col2,s_col3) values (104,444,4.04,-4);

insert into source_table(source_id,s_col1,s_col2,s_col3) values (105,555,5.05,-5);



insert into target_table(target_id,t_col1,t_col2,t_col3) values (101,null,null,null);

insert into target_table(target_id,t_col1,t_col2,t_col3) values (102,null,null,null);

insert into target_table(target_id,t_col1,t_col2,t_col3) values (103,null,null,null);

insert into target_table(target_id,t_col1,t_col2,t_col3) values (104,null,null,null);

insert into target_table(target_id,t_col1,t_col2,t_col3) values (105,null,null,null);

select * from source_table;
select * from target_table;

update
(
   select t_col1,t_col2,t_col3,s_col1,s_col2,s_col3
   from   target_table t
         ,source_table s
   where  t.target_id = s.source_id
)
set t_col1 = s_col1
   ,t_col2 = s_col2
   ,t_col3 = s_col3
;
select * from source_table;
select * from target_table;

Tuesday, August 2, 2011

[T-SQL] Wildcard

Wildcard Basics Recap

Lets start off with something most of us know already. Most SQL folks understand the usefulness and power of the basic uses of wildcards. Using wildcards allows you to do pattern matches in a column. In this case our criteria does not want to use the = sign to find a pattern match. The operator that allows you to do approximate predicates is LIKE. The LIKE operator allows you to do special relative searches to filter your result set.
--Find all LastNames that start with the letter ASELECT *FROM EmployeeWHERE LastName LIKE 'A%'
To find everyone whose last name starts with the letter B, you need “B” to be the first letter. After the letter B you can have any number of characters. Using B% in single quotes after the LIKE operator gets all last names starting with the letter B.
--Find all LastNames that start with the letter BSELECT *FROM EmployeeWHERE LastName LIKE 'B%'

Wildcard ranges or set specifiers

If you want to find all LastName values starting with the letters A or B you can use two predicates in your WHERE clause. You need to separate them with the OR operator.
--Find all LastNames that start with the letter BSELECT *FROM EmployeeWHERE LastName LIKE 'A%'OR LastName LIKE 'B%'
Finding names beginning with A or B is easy. How about the registration desk example where want the names ranging from A-K? This works well until you want a range of A-K as in the example below:
--Find all LastNames ranging from A-KSELECT *FROM EmployeeWHERE LastName LIKE 'A%'OR LastName LIKE 'B%'OR LastName LIKE 'C%'OR LastName LIKE 'D%'OR LastName LIKE 'E%'OR LastName LIKE 'F%'OR LastName LIKE 'G%'OR LastName LIKE 'H%'OR LastName LIKE 'I%'OR LastName LIKE 'J%'OR LastName LIKE 'K%'
The previous query does find LastName values starting from A-K. However, if you need a range of letters, the LIKE operator has many better options. We only really care about the first letter of the last name and there a several first letters that fit with what were looking for. The first letter of the last name can be A,B,C,D,E,F,G,H,I,J or K. Simply list all the choices you want for the first letter inside a set of square brackets.
--LastNames ranging from A to K using a set of 11 lettersSELECT *FROM EmployeeWHERE LastName LIKE '[ABCDEFGHIJK]%'
Square brackets with wildcards enclose ranges or sets for 1 position. In this case the first position is a set of 11 different possible letters. This is not a series of letter but a multiple choice of letters. For example this works regardless of the order you put your letters in. This code sample below does the exact same thing.
--LastNames ranging from A to K using a set of 11 lettersSELECT *FROM EmployeeWHERE LastName LIKE '[KBCDEFGHIJA]%'
Again the set is how many letters you put in the square brackets. The code below is a logical mistake where you won’t get A to K but you just get A or K for the first letter.
--Find all LastNames starting with A or K (MistakeSELECT *FROM EmployeeWHERE LastName LIKE '[AK]%'
Since we’re looking for the first letter to be within a range from A to K, we specify that range in square brackets. This is even easier than using a set. The wildcard after the brackets allows any number of characters after the range.
--LastNames ranging from A to K using a rangeSELECT *FROM EmployeeWHERE LastName LIKE '[A-K]%'
Note: this range will not work if your LIKE was changed to an equal (=) sign. The following code will not return any records to your result set:
--Bad query (it won’t error but returns no records)SELECT *FROM EmployeeWHERE LastName = '[A-K]%'

Wednesday, October 13, 2010

[T-SQL] Query Analyzer Shortcuts

ShortcutFunctionShortcutFunction
ALT+BREAKCancel a queryCTRL+SHIFT+F2Clear all bookmarks
ALT+F1Database object informationCTRL+SHIFT+INSERTInsert a template
ALT+F4ExitCTRL+SHIFT+LMake selection lowercase
CTRL+ASelect allCTRL+SHIFT+MReplace template parameters
CTRL+BMove the splitterCTRL+SHIFT+POpen
CTRL+CCopyCTRL+SHIFT+RRemove comment
CTRL+DDisplay results in grid formatCTRL+SHIFT+SShow client statistics
CTRL+DeleteDelete through the end of the lineCTRL+SHIFT+TShow server trace
CTRL+EExecute queryCTRL+SHIFT+UMake selection uppercase
CTRL+FFindCTRL+TDisplay results in text format
CTRL+F2Insert/remove bookmarkCTRL+UChange database
CTRL+F4DisconnectCTRL+VPaste
CTRL+F5Parse query and check syntaxCTRL+WWindow selector
CTRL+GGo to lineCTRL+XDelete
CTRL+HReplaceCTRL+ZUndo
CTRL+IIndex Tuning WizardF1Help for Query Analyzer
CTRL+KDisplay/hide execution planF2Move to next bookmark
CTRL+LDisplay execution planF3Repeat last search
CTRL+NNew query windowF4Object Search
CTRL+OConnectF5Execute a query
CTRL+PPrintF6Switch between query and result panes
CTRL+RShow/Hide results paneF8Show/hide Object Browser
CTRL+SSaveSHIFT+F1Transact-SQL help
CTRL+SHIFT+0Show optionsSHIFT+F2Move to previous bookmark
CTRL+SHIFT+CComment out codeSHIFT+TABDecrease indent
CTRL+SHIFT+DELClear the active Editor paneSHIFT+F6Switch panes
CTRL+SHIFT+FSave results to fileTABIncrease indent

Monday, October 11, 2010

[T-SQL] Get Running Query from the Sessions

If you want to get the query running of one of the session then you can get from the query below , just answering that if you want to know the running sessions then you can use sp_who and sp_who2.

Before executing this statement please change the option from result to grid to result to text. For this you can use shortcut CTRL+T.

Here is the script, 55 can be replaced from your desired session id.

DECLARE @sqltext VARBINARY(128)
SELECT @sqltext = sql_handle
FROM sys.sysprocesses
WHERE spid = 55
SELECT TEXT
FROM sys.dm_exec_sql_text(@sqltext)
GO

Wednesday, October 6, 2010

[T-SQL] Identify Blocking Query / Session

One of the most common problem that DBA faces is that one or many sessions get blocked by some sessions due to long execution or deadlock. I have many times faced this problem and also read the same problem which is faced by many DBAs every day.

Here is the query by which you can kill the blocking session:
Kill 3 ( 3 is the blocking session )

But now your question would be how to identify the blocking session , so here we go...

SELECT


db.name DBName,

tl.request_session_id,

wt.blocking_session_id,

OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,

tl.resource_type,

h1.TEXT AS RequestingText,

h2.TEXT AS BlockingTest,

tl.request_mode

FROM sys.dm_tran_locks AS tl

INNER JOIN sys.databases db ON db.database_id = tl.resource_database_id

INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address

INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id

INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id

INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id

CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1

CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2

GO

Wednesday, July 21, 2010

[T-SQL] Rebuild All Index with Fill Factor

DECLARE @TableName VARCHAR(255)
DECLARE @sql NVARCHAR(500)
DECLARE @fillfactor INT
SET @fillfactor = 80
DECLARE TableCursor CURSOR FOR
SELECT OBJECT_SCHEMA_NAME([object_id])+'.'+name AS TableName
FROM sys.tables
OPEN TableCursor
FETCH NEXT FROM TableCursor INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = 'ALTER INDEX ALL ON ' + @TableName + ' REBUILD WITH (FILLFACTOR = ' + CONVERT(VARCHAR(3),@fillfactor) + ')'
EXEC (@sql)
FETCH NEXT FROM TableCursor INTO @TableName
END
CLOSE TableCursor
DEALLOCATE TableCursor
GO

Monday, July 19, 2010

[T-Sql] Deleting Duplicate Records

Deleting Duplciate Records on any specific crieteria


DECLARE @DATE AS VARCHAR(19)
SET @DATE=(SELECT CONVERT(VARCHAR(19),ISNULL(MAX(TIMEMODIFIED),'01/01/2000'),121) FROM ACDW.DBO.QB_SALESREP)

INSERT INTO QB_SALESREP SELECT * FROM QB_SALESREP_TEMP WHERE TIMEMODIFIED>@DATE

DELETE ACDW.DBO.QB_SALESREP
FROM ACDW.DBO.QB_SALESREP TSR INNER JOIN
(
SELECT LISTID,MIN(TIMEMODIFIED) TIMEMODIFIED
FROM ACDW.DBO.QB_SALESREP
GROUP BY LISTID
HAVING COUNT(*)>1
) DD ON TSR.LISTID=DD.LISTID AND TSR.TIMEMODIFIED=DD.TIMEMODIFIED