Jeffrey Ullman ਦੇ ਮੂਹਤਵਪੂਰਨ ਵਿਚਾਰ ਅਜੋਕੀ ਡੇਟਾਬੇਸਾਂ ਨੂੰ ਕਿਵੇਂ ਚਲਾਉਂਦੇ ਹਨ: ਰਿਲੇਸ਼ਨਲ ਬੀਜਗਣਿਤ, ਓਪਟੀਮਾਈਜ਼ੇਸ਼ਨ ਨਿਯਮ, joins, ਅਤੇ ਕੰਪਾਇਲਰ-ਸ਼ੈਲੀ ਯੋਜਨਾ ਬਣਾਉਣਾ ਜੋ ਸਿਸਟਮਾਂ ਨੂੰ ਸਕੇਲ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਦਾ ਹੈ।

ਜਿਆਦਾਤਰ ਲੋਕ ਜੋ SQL ਲਿਖਦੇ ਹਨ, ਡੈਸ਼ਬੋਰਡ ਬਣਾਉਂਦੇ ਹਨ, ਜਾਂ ਕਿਸੇ ਧੀਮੀ ਕੁਇਰੀ ਨੂੰ ਟਿਊਨ ਕਰਦੇ ਹਨ, ਉਹ Jeffrey Ullman ਦੇ ਕੰਮ ਤੋਂ ਲਾਭਾਨਵੀਤ ਰਹੇ ਹਨ—ਚਾਹੇ ਉਹਨਾਂ ਨੇ ਉਸਦਾ ਨਾਮ ਸੁਣਿਆ ਵੀ ਨਾ ਹੋਵੇ। Ullman ਇੱਕ ਕੰਪਿਊਟਰ ਵਿਗਿਆਨੀ ਅਤੇ ਸਿੱਖਿਆਦਾਤਾ ਹਨ ਜਿਹਨਾਂ ਦੀਆਂ ਰਿਸਰਚ ਅਤੇ ਟੈਕਸਟਬੁੱਕ ਨੇ ਇਹ ਪਰਿਭਾਸ਼ਿਤ ਕੀਤਾ ਕਿ ਡੇਟਾਬੇਸ ਡੇਟਾ ਨੂੰ ਕਿਵੇਂ ਦਰਸਾਉਂਦੇ ਹਨ, ਕੁਇਰੀਆਂ ਬਾਰੇ ਕਿਵੇਂ ਤਰਕ ਕਰਦੇ ਹਨ, ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਕੁਸ਼ਲਤਾ ਨਾਲ ਕਿਵੇਂ ਚਲਾਇਆ ਜਾਂਦਾ ਹੈ।
ਜਦੋਂ ਕੋਈ ਡੇਟਾਬੇਸ ਇੰਜਨ ਤੁਹਾਡੇ SQL ਨੂੰ ਇਸ ਤਰ੍ਹਾਂ ਬਦਲਦਾ ਹੈ ਕਿ ਉਹ ਤੇਜ਼ ਚੱਲ ਸਕੇ, ਤਾਂ ਉਹ ਅਜਿਹੀਆਂ ਵਿਚਾਰਧਾਰਾਵਾਂ 'ਤੇ ਨਿਰਭਰ ਕਰ ਰਿਹਾ ਹੁੰਦਾ ਹੈ ਜੋ ਬਹੁਤ ਨਿਰਧਾਰਤ ਅਤੇ ਲਚਕੀਲੀਆਂ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਨੇ। Ullman ਨੇ ਕੁਇਰੀਆਂ ਦੇ ਅਰਥ ਨੂੰ ਫਾਰਮਲ ਕੀਤਾ (ਤਾਂ ਜੋ ਸਿਸਟਮ ਉਨ੍ਹਾਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਢੰਗ ਨਾਲ ਰੀਰਾਈਟ ਕਰ ਸਕੇ), ਅਤੇ ਉਸਨੇ ਡੇਟਾਬੇਸ ਸੋਚ ਨੂੰ ਕੰਪਾਇਲਰ ਸੋਚ ਨਾਲ ਜੋੜਿਆ (ਤਾਂ ਜੋ ਇੱਕ ਕੁਇਰੀ ਨੂੰ parse, optimize, ਅਤੇ executable ਕਦਮਾਂ ਵਿੱਚ ਤਬਦੀਲ ਕੀਤਾ ਜਾ ਸਕੇ)।
ਇਹ ਪ੍ਰਭਾਵ ਚੁਪ ਹੈ ਕਿਉਂਕਿ ਇਹ ਤੁਹਾਡੇ BI ਟੂਲ ਵਿੱਚ ਕੋਈ ਬਟਨ ਜਾਂ ਕਲਾਉਡ ਕਨਸੋਲ ਵਿੱਚ ਕੋਈ ਦਿੱਖ-ਯੋਗ ਫੀਚਰ ਵਜੋਂ ਨਹੀਂ ਆਉਂਦਾ। ਇਹ ਨਤੀਜੇ ਵਜੋਂ ਦਿਖਾਈ ਦਿੰਦਾ ਹੈ:
JOIN ਨੂੰ ਦੁਬਾਰਾ ਲਿਖਦੇ ਹੋਇਹ ਪੋਸਟ Ullman ਦੇ ਮੁੱਖ ਵਿਚਾਰਾਂ ਨੂੰ ਵਰਤਦਿਆਂ ਉਹ ਡੇਟਾਬੇਸ ਅੰਦਰੂਨੀ ਗੱਲਾਂ ਦਾ ਦਰਸਨ ਕਰਵਾਉਂਦੀ ਹੈ ਜੋ ਅਮਲ ਵਿੱਚ ਸਭ ਤੋਂ ਜ਼ਿਆਦਾ ਮਹੱਤਵ ਰੱਖਦੀਆਂ ਹਨ: SQL ਦੇ ਨੀਵੇਂ ਰਿਹਾ ਰਿਲੇਸ਼ਨਲ ਬੀਜਗਣਿਤ ਕਿਵੇਂ ਬੈਠਦੀ ਹੈ, ਕੁਇਰੀ ਰੀਰਾਈਟਸ ਦਾ ਮਤਲਬ ਕਿਵੇਂ ਸੁਰੱਖਿਅਤ ਰਹਿੰਦਾ ਹੈ, ਕੋਸਟ-ਅਧਾਰਿਤ ਓਪਟੀਮਾਈਜ਼ਰ ਕਿਉਂ ਉਹ ਫੈਸਲੇ ਕਰਦੇ ਹਨ ਜੋ ਉਹ ਕਰਦੇ ਹਨ, ਅਤੇ ਜੋਇਨ ਅਲਗੋਰਿਦਮ ਅਕਸਰ ਇਹ ਤੈਅ ਕਰਦੇ ਹਨ ਕਿ ਇੱਕ ਕੰਮ ਸੈਕਿੰਡਾਂ ਵਿੱਚ ਖਤਮ ਹੋਵੇ ਜਾਂ ਘੰਟਿਆਂ ਵਿੱਚ।
ਅਸੀਂ ਕੁਝ ਕੰਪਾਇਲਰ-ਨੁਮਾ ਸੰਕਲਪ ਵੀ ਲਿਆਉਂਦੇ ਹੋਵਾਂਗੇ—parsing, rewriting, ਅਤੇ planning—ਕਿਉਂਕਿ ਡੇਟਾਬੇਸ ਇੰਜਨ ਬਹਿਸ਼ਕ ਕੰਪਾਇਲਰਾਂ ਦੇ ਬਹੁਤ ਹੀ ਉੱਨਤ ਵਰਜ਼ਨ ਵਾਂਗ ਵਰਤਦੇ ਹਨ।
ਇੱਕ ਛੋਟੀ ਵਾਅਦਾ: ਅਸੀਂ ਚਰਚਾ ਨੂੰ ਸਹੀ ਰੱਖਾਂਗੇ ਪਰ ਗਣਿਤੀ ਸਬੂਤਾਂ ਤੋਂ ਬਚਾਂਗੇ। ਲਕਸ਼ ਹੈ ਕਿ ਤੁਸੀਂ ਅਗਲੀ ਵਾਰੀ ਜਦੋਂ ਪ੍ਰਦਰਸ਼ਨ, ਸਕੇਲ, ਜਾਂ ਗੁੰਝਲਦਾਰ ਕੁਇਰੀ ਵਿਵਹਾਰ ਆਵੇ ਤਾਂ ਕਾਰਜ-ਯੋਗ ਮਾਨਸਿਕ ਮਾਡਲ ਲੈ ਕੇ ਜਾ ਸਕੋ।
ਜੇ ਤੁਸੀਂ ਕਦੇ SQL ਲਿਖੀ ਹੈ ਅਤੇ ਉਮੀਦ ਕੀਤੀ ਕਿ ਇਹ "ਸਿਰਫ ਇਕ ਹੀ ਮਤਲਬ ਰੱਖਦੀ ਹੈ," ਤਾਂ ਤੁਸੀਂ ਉਹਨਾਂ ਧਾਰਾਵਾਂ 'ਤੇ ਨਿਰਭਰ ਕਰ ਰਹੇ ਹੋ ਜੋ Jeffrey Ullman ਨੇ ਲੋਕਪ੍ਰিয় ਅਤੇ ਫਾਰਮਲ ਕੀਤੀਆਂ: ਡੇਟਾ ਲਈ ਇੱਕ ਸਾਫ ਮਾਡਲ, ਅਤੇ ਉਹ ਤਰੀਕੇ ਜੋ ਕੁਇਰੀ ਕੀ ਮੰਗ ਨੂੰ ਨਿਰਧਾਰਤ ਕਰਦੇ ਹਨ।
ਮੂਲ ਰੂਪ ਵਿੱਚ, ਰਿਲੇਸ਼ਨਲ ਮਾਡਲ ਡੇਟਾ ਨੂੰ ਟੇਬਲਾਂ (relations) ਵਜੋਂ ਮੰਨਦਾ ਹੈ। ਹਰ ਟੇਬਲ ਵਿੱਚ ਕਤਾਰਾਂ (tuples) ਅਤੇ ਕਾਲਮ (attributes) ਹੁੰਦੇ ਹਨ। ਹੁਣ ਇਹ ਆਮ ਗੱਲ ਲੱਗਦੀ ਹੈ, ਪਰ ਮਹੱਤਵਪੂਰਨ ਗੱਲ ਇਹ ਹੈ ਕਿ ਇਹ ਕਿਸ ਤਰ੍ਹਾਂ ਦਾ ਅਨੁਸ਼ਾਸਨ ਬਣਾਉਂਦਾ ਹੈ:
ਇਹ ਸੰਜੋਗ ਸਹੀਪਨ ਅਤੇ ਪ੍ਰਦਰਸ਼ਨ ਬਾਰੇ ਹੱਥ-ਹਵਾਲੇ ਤਰਕ ਕਰਨ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਜਦੋਂ ਤੁਸੀਂ ਜਾਣਦੇ ਹੋ ਕਿ ਇੱਕ ਟੇਬਲ ਕੀ ਦਰਸਾਂਦੀ ਹੈ ਅਤੇ ਕਿਵੇਂ ਕਤਾਰਾਂ ਦੀ ਪਛਾਣ ਹੁੰਦੀ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਅਣੂਮਾਨ ਲਗਾ ਸਕਦੇ ਹੋ ਕਿ joins ਕੀ ਕਰਨਗੇ, duplicates ਕਿਉਂ ਹਨ, ਅਤੇ ਕਿਉਂ ਕੁਝ ਫਿਲਟਰ ਨਤੀਜਿਆਂ ਨੂੰ ਬਦਲ ਦਿੰਦੇ ਹਨ।
Ullman ਦੀ ਸਿੱਖਿਆ ਆਮ ਤੌਰ 'ਤੇ ਰਿਲੇਸ਼ਨਲ ਬੀਜਗਣਿਤ ਨੂੰ ਇੱਕ ਕਿਸਮ ਦਾ ਕੁਇਰੀ ਕੈਲਕੁਲੇਟਰ ਵਜੋਂ ਵਰਤਦੀ ਹੈ: ਇੱਕ ਛੋਟਾ ਸੈੱਟ ਓਪਰੇਸ਼ਨਾਂ (select, project, join, union, difference) ਜੋ ਤੁਸੀਂ ਮਿਲਾ ਕੇ ਆਪਣੀ ਮੰਗ ਨੂੰ ਵਿਆਖਿਆ ਕਰ ਸਕਦੇ ਹੋ।
ਕਾਮ ਦੀ ਗੱਲ ਇਹ ਹੈ ਕਿ ਡੇਟਾਬੇਸ SQL ਨੂੰ ਇੱਕ ਐਲਜਬ੍ਰਿਕ ਫਾਰਮ ਵਿੱਚ ਤਬਦੀਲ ਕਰਦੇ ਹਨ ਅਤੇ ਫਿਰ ਇਸ ਨੂੰ ਇਕ ਸਮਤੁਲ ਰੂਪ ਵਿੱਚ ਰੀਰਾਈਟ ਕਰਦੇ ਹਨ। ਦੋ ਕੁਇਰੀਆਂ ਜੋ ਵੱਖਰਾ ਦਿਖਦੀਆਂ ਹਨ ਉਹ algebraic ਤੌਰ 'ਤੇ ਇਕੋ ਹੀ ਹੋ ਸਕਦੀਆਂ ਹਨ—ਇਸੇ ਤਰ੍ਹਾਂ ਓਪਟੀਮਾਈਜ਼ਰ joins ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮਬੱਧ ਕਰ ਸਕਦੇ ਹਨ, ਫਿਲਟਰਾਂ ਨੂੰ ਅੱਗੇ ਧੱਕ ਸਕਦੇ ਹਨ, ਜਾਂ ਫੁਨਕਸ਼ਨਲ ਕੰਮ ਹਟਾ ਸਕਦੇ ਹਨ ਬਿਨਾਂ ਅਰਥ ਬਦਲੇ।
SQL ਜ਼ਿਆਦਾਤਰ "ਕੀ" ਦੀ ਭਾਸ਼ਾ ਹੈ, ਪਰ ਇੰਜਨ ਆਮ ਤੌਰ 'ਤੇ ਐਲਜਬ੍ਰਿਕ "ਕਿਵੇਂ" ਵਰਤ ਕੇ ਓਪਟੀਮਾਈਜ਼ ਕਰਦੇ ਹਨ।
SQL ਡਾਇਲੈਕਟ ਵੱਖ-ਵੱਖ ਹੋ ਸਕਦੇ ਹਨ (Postgres ਵਿਰੁੱਧ Snowflake ਵਿਰੁੱਧ MySQL), ਪਰ ਮੂਲ ਗੱਲਾਂ ਨਹੀਂ ਬਦਲਦੀਆਂ। ਕੀ, ਰਿਸ਼ਤੇ ਅਤੇ ਐਲਜਬ੍ਰਿਕ ਸਮਤੁਲਤਾ ਦੀ ਸਮਝ ਤੁਹਾਨੂੰ ਦੱਸਦੀ ਹੈ ਕਿ ਜਦੋਂ ਇੱਕ ਕੁਇਰੀ ਤਾਰਕਿਕ ਤੌਰ 'ਤੇ ਗਲਤ ਹੈ, ਜਦੋਂ ਉਹ ਸਿਰਫ ਧੀਮੀ ਹੈ, ਅਤੇ ਕਿਹੜੇ ਬਦਲਾਅ ਮਤਲਬ ਨੂੰ ਕਾਇਮ ਰੱਖਦੇ ਹਨ।
ਰਿਲੇਸ਼ਨਲ ਬੀਜਗਣਿਤ SQL ਦਾ "ਹੇਠਲਾ ਗਣਿਤ" ਹੈ: ਕੁਝ ਓਪਰੇਟਰਾਂ ਦਾ ਸੈੱਟ ਜੋ ਤੁਸੀਂ ਇਕੱਠੇ ਕਰਕੇ ਉਹ ਨਤੀਜਾ ਦਰਸਾ ਸਕਦੇ ਹੋ ਜੋ ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ। Jeffrey Ullman ਦਾ ਕੰਮ ਇਸ ਓਪਰੇਟਰ-ਦੇਖ ਨੂੰ ਸਾਫ ਅਤੇ ਸਿਖਣਯੋਗ ਬਣਾਉਣ ਵਿੱਚ ਮਦਦਗਾਰ ਰਿਹਾ—ਅਤੇ ਅਜੇ ਵੀ ਜ਼ਿਆਦਾਤਰ ਓਪਟੀਮਾਈਜ਼ਰਾਂ ਦੀ ਮਾਨਸਿਕ ਮਾਡਲ यही ਹੈ।
ਇੱਕ ਡੇਟਾਬੇਸ ਕੁਇਰੀ ਕੁਝ ਇਕਾਈ ਨਿਰਮਾਣ-ਪੱਧਰਾਂ ਦੇ ਤੌਰ 'ਤੇ ਦਰਸਾਈ ਜਾ ਸਕਦੀ ਹੈ:
WHERE)SELECT col1, col2)JOIN ... ON ...)UNION)EXCEPT ਵਰਗਿਆ)ਇਸ ਛੋਟੀ ਸੈੱਟ ਕਾਰਨ, correctness ਬਾਰੇ ਤਰਕ ਕਰਨਾ ਆਸਾਨ ਹੋ ਜਾਂਦਾ ਹੈ: ਜੇ ਦੋ ਐਲਜਬ੍ਰਿਕ ਪ੍ਰਕਿਰਿਆਵਾਂ ਸਮਾਨ ਹਨ, ਉਹ ਕਿਸੇ ਵੀ ਵੈਧ ਡੇਟਾਬੇਸ ਸਥਿਤੀ ਲਈ ਇਕੋ-ਓਹੀ ਟੇਬਲ ਵਾਪਸ ਕਰਦੀਆਂ ਹਨ।
ਇੱਕ ਜਾਣ-ਪਛਾਣ ਵਾਲੀ ਕੁਇਰੀ ਲਓ:
SELECT c.name
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.total > 100;
ਆਮ ਤੌਰ 'ਤੇ, ਇਹ ਹੈ:
ਇੱਕ join ਨਾਲ customers ਅਤੇ orders ਦੀ ਸ਼ੁਰੂਆਤ: customers ⋈ orders
ਸਿਰਫ਼ ਉਹ orders ਚੁਣੋ ਜਿਨ੍ਹਾਂ ਦੀ ਕੁੱਲ ਰਕਮ 100 ਤੋਂ ਵੱਧ ਹੈ: σ(o.total > 100)(...)
ਜੋ ਕਾਲਮ ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ ਉਹ ਪ੍ਰੋਜੈਕਟ ਕਰੋ: π(c.name)(...)
ਇਹ ਹਰ ਇੰਜਨ ਦੇ ਅੰਦਰੂਨੀ ਨੋਟੇਸ਼ਨ ਦੇ bilkul exact ਨ ਹੋ ਸਕਦਾ ਪਰ ਆਈਡਿਆ ਸਹੀ ਹੈ: SQL ਇੱਕ ਓਪਰੇਟਰ ਟ੍ਰੀ ਬਣ ਜਾਂਦੀ ਹੈ।
ਬਹੁਤ ਸਾਰੀਆਂ ਵੱਖ-ਵੱਖ ਟ੍ਰੀਜ਼ ਇੱਕੋ ਨਤੀਜੇ ਨੂੰ ਦਰਸਾ ਸਕਦੀਆਂ ਹਨ। ਉਦਾਹਰਨ ਲਈ, ਫਿਲਟਰ ਆਮ ਤੌਰ 'ਤੇ ਪਹਿਲਾਂ ਲਾਇਆ ਜਾ ਸਕਦਾ ਹੈ (ਬੱਡੇ join ਤੋਂ ਪਹਿਲਾਂ σ ਲਗਾਉਣਾ), ਅਤੇ ਪ੍ਰੋਜੈਕਸ਼ਨ ਅਕਸਰ ਬਿਨਾਂ ਲੋੜ ਦੇ ਕਾਲਮ ਪਹਿਲਾਂ ਹੀ ਹਟਾ ਸਕਦੀ ਹੈ (ਪਹਿਲਾਂ π ਲਗਾਉਣਾ)।
ਇਹ ਸਮਤੁਲਤਾ ਨਿਯਮ ਡੇਟਾਬੇਸ ਨੂੰ ਤੁਹਾਡੀ ਕੁਇਰੀ ਨੂੰ ਇੱਕ ਸਸਤੀ ਯੋਜਨਾ ਵਿੱਚ ਰੀਰਾਈਟ ਕਰਨ ਦਿੰਦੇ ਹਨ ਬਿਨਾਂ ਅਰਥ ਬਦਲੇ। ਇੱਕ ਵਾਰੀ ਤੁਸੀਂ ਕੁਇਰੀਆਂ ਨੂੰ ਐਲਜਬ੍ਰਿਕ ਰੂਪ ਵਿੱਚ ਦੇਖਦੇ ਹੋ, ਤਾਂ "ਓਪਟੀਮਾਈਜ਼ੇਸ਼ਨ" ਜਾਦੂ ਨਹੀਂ ਰਹਿੰਦੀ—ਇਹ ਨਿਯਮਾਂ ਤੇ ਆਧਾਰਤ ਇਕ ਸੁਰੱਖਿਅਤ ਰੀਸ਼ੇਪਿੰਗ ਹੁੰਦੀ ਹੈ।
ਜਦੋਂ ਤੁਸੀਂ SQL ਲਿਖਦੇ ਹੋ, ਡੇਟਾਬੇਸ ਉਹਨੂੰ "ਜਿਵੇਂ ਲਿਖਿਆ" ਨਹੀਂ ਚਲਾਉਂਦਾ। ਇਹ ਤੁਹਾਡੇ ਬਿਆਨ ਨੂੰ ਇੱਕ ਕੁਇਰੀ ਯੋਜਨਾ ਵਿੱਚ ਤਬਦੀਲ ਕਰਦਾ ਹੈ: ਕੰਮ ਦੀ ਇੱਕ ਸਰਚਿਤ ਪ੍ਰਤਿਨਿਧੀ।
ਇੱਕ ਚੰਗੀ ਮਾਨਸਿਕ ਤਸਵੀਰ ਇੱਕ ਓਪਰੇਟਰ ਟ੍ਰੀ ਦੀ ਹੈ। ਪੱਤਿਆਂ ਉੱਤੇ ਟੇਬਲ ਜਾਂ ਇੰਡੈਕਸ ਪੜ੍ਹਦੇ ਹਨ; ਅੰਦਰੂਨੀ ਨੋਡ ਕਤਾਰਾਂ ਨੂੰ ਤਬਦੀਲ ਅਤੇ ਮਿਲਾਉਂਦੇ ਹਨ। ਆਮ ਓਪਰੇਟਰਾਂ ਵਿੱਚ scan, filter (selection), project (columns ਚੁਣਨਾ), join, group/aggregate, ਅਤੇ sort ਸ਼ਾਮਲ ਹਨ।
ਡੇਟਾਬੇਸ ਆਮ ਤੌਰ 'ਤੇ ਯੋਜਨਾ ਨੂੰ ਦੋ ਪਰਤਾਂ ਵਿੱਚ ਵੰਡਦੇ ਹਨ:
Ullman ਦਾ ਪ੍ਰਭਾਵ "ਅਰਥ-ਰੱਖਣ ਵਾਲੀ ਬਦਲੀ" 'ਤੇ ਟਿਕਿਆ ਹੋਇਆ ਹੈ: ਲਾਜ਼ਮੀ ਯੋਜਨਾ ਨੂੰ ਬੇਅੰਤੀ ਗਿਣਤ ਤਰੀਕਿਆਂ ਨਾਲ ਦੁਬਾਰਾ ਵਿਵਸਥਿਤ ਕਰੋ ਬਿਨਾਂ ਜਵਾਬ ਬਦલે, ਫਿਰ ਇੱਕ ਪ੍ਰਭਾਵਸ਼ালী ਭੌਤਿਕ ਰਣਨੀਤੀ ਚੁਣੋ।
ਅੰਤਿਮ ਐਗਜ਼ਿਕਿਊਸ਼ਨ ਚੁਣਨ ਤੋਂ ਪਹਿਲਾਂ, ਓਪਟੀਮਾਈਜ਼ਰ ਐਲਜਬ੍ਰਿਕ "ਸਫਾਈ" ਨਿਯਮ ਲਗਾਉਂਦੇ ਹਨ। ਇਹ ਰੀਰਾਈਟਸ ਨਤੀਜੇ ਨਹੀਂ ਬਦਲਦੇ; ਪਰ ਇਹ ਬੇਲੋੜਾ ਕੰਮ ਘਟਾ ਦਿੰਦੇ ਹਨ।
ਆਮ ਉਦਾਹਰਣ:
ਮਾਨ ਲਓ ਤੁਸੀਂ ਕਿਸੇ ਦੇਸ਼ ਦੇ ਉਪਭੋਗਤਿਆਂ ਦੇ ਆਰਡਰ ਚਾਹੁੰਦੇ ਹੋ:
SELECT o.order_id, o.total
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE u.country = 'CA';
ਇੱਕ ਨਾਹੀਵ ਰੂਪ ਅਕਸਰ ਸਾਰੇ users ਨੂੰ ਸਾਰੀਆਂ orders ਨਾਲ ਜੋੜ ਕੇ ਫਿਰ Canada ਫਿਲਟਰ ਕਰੇਗਾ। ਇੱਕ ਅਰਥ-ਰੱਖਣ ਵਾਲਾ ਰੀਰਾਈਟ ਫਿਲਟਰ ਨੂੰ ਅੱਗੇ ਧੱਕਦਾ ਹੈ ਤਾਂ ਜੋ join ਘੱਟ ਕਤਾਰਾਂ 'ਤੇ ਲਾਗੂ ਹੋਵੇ:
country = 'CA' ਲਈ ਫਿਲਟਰ ਕਰੋorder_id ਅਤੇ total ਪ੍ਰੋਜੈਕਟ ਕਰੋਯੋਜਨਾ ਟਰਮੀਨਲੋਜੀ ਵਿੱਚ, ਓਪਟੀਮਾਈਜ਼ਰ ਇਸਨੂੰ ਇਸ ਤਰ੍ਹਾਂ ਬਦਲਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦਾ ਹੈ:
Join(Users, Orders) → Filter(country='CA') → Project(order_id,total)
ਨੂੰ ਕੁਝ ਇਸ ਦੇ ਨੇੜੇ:
Filter(country='CA') on Users → Join(with Orders) → Project(order_id,total)
ਉਹੀ ਜਵਾਬ। ਘੱਟ ਕੰਮ।
ਇਹ ਰੀਰਾਈਟਸ ਆਸਾਨੀ ਨਾਲ ਨਜ਼ਰਅੰਦਾਜ਼ ਹੋ ਸਕਦੇ ਹਨ ਕਿਉਂਕਿ ਤੁਸੀਂ ਕਿਸੇ ਨੂੰ ਟਾਈਪ ਨਹੀਂ ਕਰਦੇ—ਫਿਰ ਵੀ ਇਹ ਇੱਕ ਵੱਡਾ ਕਾਰਣ ਹੈ ਕਿ ਇਕੋ ਹੀ SQL ਇੱਕ ਡੇਟਾਬੇਸ 'ਤੇ ਤੇਜ਼ ਅਤੇ ਦੂਜੇ 'ਤੇ ਧੀਮਾ ਚਲ ਸਕਦੀ ਹੈ।
ਜਦੋਂ ਤੁਸੀਂ SQL ਚਲਾਉਂਦੇ ਹੋ, ਡੇਟਾਬੇਸ ਇਕੋ ਨਤੀਜੇ ਦੇਣ ਵਾਲੀਆਂ ਕਈ ਵਿਵਿਧ ਯੋਜਨਾਵਾਂ 'ਤੇ ਵਿਚਾਰ ਕਰਦਾ ਹੈ ਅਤੇ ਫਿਰ ਉਹ ਚੁਣਦਾ ਹੈ ਜਿਸਦੀ ਲਾਗਤ ਉਸ ਨੂੰ ਸਭ ਤੋਂ ਸਸਤੀ ਲੱਗਦੀ ਹੈ। ਇਹ ਫੈਸਲਾ ਪ੍ਰਕਿਰਿਆ ਹੀ ਹੈ ਜਿਸਨੂੰ cost-based optimization ਕਹਿੰਦੇ ਹਨ—ਅਤੇ ਇਹ ਅਜਿਹੀ ਥਾਂ ਹੈ ਜਿੱਥੇ Ullman-ਸ਼ੈਲੀ ਦਾ ਸਿਧਾਂਤ ਰੋਜ਼ਮਰਾ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ 'ਚ ਦਰਸਦਾ ਹੈ।
ਇਕ ਕੋਸਟ ਮਾਡਲ ਇੱਕ ਸਕੋਰਿੰਗ ਸسٽਮ ਹੈ ਜੋ ਓਪਟੀਮਾਈਜ਼ਰ ਵੱਖ-ਵੱਖ ਯੋਜਨਾਵਾਂ ਦੀ ਤੁਲਨਾ ਕਰਨ ਲਈ ਵਰਤਦਾ ਹੈ। ਜ਼ਿਆਦਾਤਰ ਇੰਜਨ ਕੁਝ ਮੁੱਖ ਸਰੋਤਾਂ ਦੀ ਆਧਾਰ 'ਤੇ ਲਾਗਤ ਅੰਦਾਜ਼ਾ ਲਗਾਉਂਦੇ ਹਨ:
ਮਾਡਲ ਨੂੰ ਪਰਫੈਕਟ ਹੋਣ ਦੀ ਲੋੜ ਨਹੀਂ; ਉਸਨੂੰ ਅਕਸਰ ਕਿਦਰ ਸੁਝਾਅ ਦੇਣਾ ਚਾਹੀਦਾ ਹੈ ਤਾ ਕਿ ਵਧੀਆ ਯੋਜ਼ਨਾ ਚੁਣੀ ਜਾ ਸਕੇ।
ਯੋਜਨਾ ਨੂੰ ਅੰਕੜਾ ਲਗਾਉਣ ਤੋਂ ਪਹਿਲਾਂ, optimizer ਹਰ ਕਦਮ 'ਤੇ ਪੁੱਛਦਾ ਹੈ: ਇਸ ਤੋਂ ਕਿੰਨੀ ਕਤਾਰਾਂ ਨਿਕਲਣਗੀਆਂ? ਇਹੇ cardinality estimation ਹੈ।
ਜੇ ਤੁਸੀਂ WHERE country = 'CA' ਫਿਲਟਰ ਲਗਾਉਂਦੇ ਹੋ, ਤਾਂ ਇੰਜਨ ਅੰਦਾਜ਼ਾ ਲਗਾਏਗਾ ਕਿ ਟੇਬਲ ਦਾ ਕਿੰਨਾ ਹਿਸਾ ਮਿਲੇਗਾ। ਜੇ ਤੁਸੀਂ customers ਨੂੰ orders ਨਾਲ join ਕਰਦੇ ਹੋ, ਤਾਂ ਉਹ ਅੰਦਾਜ਼ਾ ਲਗਾਏਗਾ ਕਿ ਕਿੰਨੇ ਜੋੜ-ਜੋੜੀ ਮਿਲਣਗੀਆਂ। ਇਹ ਰੋ-ਕਾਉਂਟ ਅੰਦਾਜ਼ੇ ਇਹ ਨਿਰਧਾਰਿਤ ਕਰਦੇ ਹਨ ਕਿ ਉਹ index scan ਨੂੰ full scan ਨਾਲ ਤਲਣਾ, hash join ਕਰਨਾ ਜਾਂ nested loop ਵਰਤਣਾ ਚਾਹੇ।
ਓਪਟੀਮਾਈਜ਼ਰ ਦੇ ਅੰਦਾਜ਼ੇ statistics 'ਤੇ ਆਧਾਰਿਤ ਹੁੰਦੇ ਹਨ: ਗਿਣਤੀਆਂ, ਮੁੱਲਾਂ ਦੀ ਵੰਡ, null ਦਰਾਂ, ਅਤੇ ਕਈ ਵਾਰ ਕਾਲਮਾਂ ਵਿਚਕਾਰ correlation ਵੀ।
ਜਦੋਂ stats stale ਜਾਂ ਗੈਰ-ਮੌਜੂਦ ਹੁੰਦੇ ਹਨ, ਤਾ ਐਂਜਨ ਕਤਾਰਾਂ ਦਾ ਅੰਦਾਜ਼ਾ ਕਈ ਗੁਣਾ ਗਲਤ ਕਰ ਸਕਦਾ ਹੈ। ਇੱਕ ਯੋਜਨਾ ਜੋ ਕਾਗਜ਼ 'ਤੇ ਸਸਤੀ ਲੱਗਦੀ ਸੀ, ਅਸਲियत ਵਿੱਚ ਮਹਿੰਗੀ ਸਾਬਤ ਹੋ ਸਕਦੀ ਹੈ—ਇਸ ਦੇ ਲੱਛਣਾਂ ਵਿੱਚ ਡੇਟਾ ਵਧਣ ਦੇ ਬਾਅਦ ਅਚਾਨਕ ਹੌਲੀ ਹੋਣਾ, "ਰੈਂਡਮ" ਯੋਜਨਾਬਦਲ, ਜਾਂ joins ਜੋ ਅਣਉਮੀਦ ਤੌਰ 'ਤੇ ਡਿਸਕ 'ਤੇ spill ਹੋ ਰਹੇ ਹਨ ਸ਼ਾਮਲ ਹਨ।
ਚੰਗੇ ਅੰਦਾਜ਼ੇ ਅਕਸਰ ਵਧੇਰੇ ਕੰਮ ਮੰਗਦੇ ਹਨ: ਜ਼ਿਆਦਾ ਵੇਰਵਾ ਵਾਲੀ stats, ਨਮੂਨਾ ਲੈਣਾ, ਜਾਂ ਹੋਰ ਉਮੀਦਵਾਰ ਯੋਜਨਾਵਾਂ ਦੀ ਜਾਂਚ। ਪਰ ਯੋਜਨਾ ਬਣਾਉਣ ਖੁਦ ਵੀ ਸਮਾਂ ਲੈਂਦੀ ਹੈ, ਖ਼ਾਸ ਕਰਕੇ ਜਟਿਲ ਕੁਇਰੀਆਂ ਲਈ।
ਇਸ ਲਈ ਓਪਟੀਮਾਈਜ਼ਰ ਦੋ ਲਕੜਾਂ ਵਿੱਚ ਸੰਤੁਲਨ ਬਣਾਂਦੇ ਹਨ:
EXPLAIN ਆਉਟਪੁੱਟ ਨੂੰ ਸਮਝਦੇ ਸਮੇਂ ਇਹ ਟਰੇਡ-ਆਫ ਯਾਦ ਰੱਖਣਾ ਮਦਦਗਾਰ ਹੁੰਦਾ ਹੈ: ਓਪਟੀਮਾਈਜ਼ਰ ਚਾਲਾਕੀ ਨਹੀਂ ਕਰ ਰਿਹਾ—ਉਹ ਸੀਮਤ ਜਾਣਕਾਰੀ ਹੇਠਾਂ ਪ੍ਰੀਡਿਕਟਬਲ ਤੌਰ 'ਤੇ ਸਹੀ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਿਹਾ ਹੈ।
Ullman ਦਾ ਕੰਮ ਇੱਕ ਸਧਾਰਨ ਪਰ ਤਾਕਤਵਰ ਵਿਚਾਰ ਨੂੰ ਪ੍ਰਸਿੱਧ ਕਰਨ ਵਿੱਚ ਮਦਦਗਾਰ ਰਿਹਾ: SQL ਨੂੰ "ਚਲਾਇਆ" ਨਹੀਂ ਜਾਂਦਾ, ਬਲਕਿ ਇਹਨੂੰ ਇੱਕ ਐਗਜ਼ਿਕਿਊਸ਼ਨ ਯੋਜਨਾ ਵਿੱਚ ਅਨੁਵਾਦ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਇਹ ਸਭ ਤੋਂ ਜ਼ਿਆਦਾ joins 'ਚ ਸਪੱਸ਼ਟ ਹੁੰਦਾ ਹੈ। ਦੋ ਕੁਇਰੀਆਂ ਜੋ ਇਕੋ ਲਾਈਨਾਂ ਵਾਪਸ ਕਰਦੀਆਂ ਹਨ, ਉਹਨਾਂ ਦੀ ਰਨਟਾਈਮ ਭਰਪੂਰ ਤਰੀਕੇ ਨਾਲ ਵੱਖਰੀ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ 'ਤੇ ਨਿਰਭਰ ਕਰ ਕੇ ਕਿ ਇੰਜਨ ਕਿਹੜਾ join algorithm ਚੁਣਦਾ ਹੈ—ਅਤੇ ਕਿਹੜੇ ਕ੍ਰਮ ਵਿੱਚ ਉਹ tables ਨੂੰ ਜੋੜਦਾ ਹੈ।
Nested loop join ਸਿਧਾ ਹੈ: ਖੱਬੇ ਪਾਸੇ ਦੀ ਹਰ ਕਤਾਰ ਲਈ ਸੱਜੇ ਪਾਸੇ ਦੀਆਂ ਮੇਲ ਖੋਜੋ। ਜਦੋਂ ਖੱਬਾ ਛੋਟਾ ਹੋ ਅਤੇ ਸੱਜਾ ਇੰਡੈਕਸ ਨਾਲ ਤੇਜ਼ੀ ਨਾਲ ਚੈੱਕ ਹੋ ਸਕੇ ਤਾਂ ਇਹ ਤੇਜ਼ ਹੋ ਸਕਦਾ ਹੈ।
Hash join ਇੱਕ ਇਨਪੁੱਟ (ਅਕਸਰ ਛੋਟਾ) ਤੋਂ ਇੱਕ ਹੈਸ਼ ਟੇਬਲ ਬਣਾਉਂਦਾ ਹੈ ਅਤੇ ਦੂਜੇ ਤੋਂ probe ਕਰਦਾ ਹੈ। ਇਹ ਬੜੇ, ਅਸਰਗਤ ਇਨਪੁੱਟਾਂ ਲਈ ਚਮਕਦਾਰ ਹੁੰਦਾ ਹੈ ਜਦੋਂ شرط equality ਹੋਵੇ (ਜਿਵੇਂ A.id = B.id), ਪਰ ਇਹ ਮੈਮੋਰੀ ਮੰਗਦਾ ਹੈ; ਜੇ spill-to-disk ਹੁੰਦਾ ਹੈ ਤਾਂ ਫਾਇਦਾ ਖਤਮ ਹੋ ਸਕਦਾ ਹੈ।
Merge join ਦੋਵੇਂ ਇਨਪੁੱਟਾਂ ਨੂੰ sort ਕੀਤੇ ਹੋਏ ਕ੍ਰਮ ਵਿੱਚ ਚਲਾਉਂਦਾ ਹੈ। ਜਦੋਂ ਦੋਹਾਂ ਪਾਸੇ ਪਹਿਲਾਂ ਤੋਂ order ਹੋਵੇ (ਜਾਂ indexes ਤੋਂ join-key ਕ੍ਰਮ ਸਸਤੇ ਮਿਲਦੇ ਹੋਣ), ਇਹ ਬਹੁਤ ਵਧੀਆ ਫਿੱਟ ਹੁੰਦਾ ਹੈ।
ਤਿੰਨ ਜਾਂ ਵੱਧ ਟੇਬਲਾਂ ਨਾਲ, ਸੰਭਵ join ਆਰਡਰਾਂ ਦੀ ਗਿਣਤੀ ਬਹੁਤ ਵਧ ਜਾਂਦੀ ਹੈ। ਪਹਿਲਾਂ ਦੋ ਵੱਡੀਆਂ ਟੇਬਲਾਂ ਜੋੜਨਾ ਇੱਕ ਵੱਡਾ intermediate ਨਤੀਜਾ ਪੈਦਾ ਕਰ ਸਕਦਾ ਹੈ ਜੋ ਬਾਕੀ ਕੰਮ ਨੂੰ ਧੀਮਾ ਕਰ ਦੇਵੇ। ਇੱਕ ਚੰਗਾ ਕ੍ਰਮ ਆਮ ਤੌਰ 'ਤੇ ਸਭ ਤੋਂ ਚੁਣਿੰਦਰ (selective) ਫਿਲਟਰ ਤੋਂ ਸ਼ੁਰੂ ਕਰਦਾ ਹੈ ਅਤੇ ਬਾਹਰ ਵੱਲ join ਕਰਦਾ ਹੈ, intermediates ਨੂੰ ਛੋਟਾ ਰੱਖਣ ਲਈ।
ਇੰਡੈਕਸ ਸਿਰਫ lookup ਤੇ ਰਫਤਾਰ ਨਹੀਂ ਲਿਆਉਂਦੇ—ਉਹ ਕੁਝ join ਰਣਨੀਤੀਆਂ ਨੂੰ viable ਬਣਾਉਂਦੇ ਹਨ। join key 'ਤੇ ਇੰਡੈਕਸ ਇੱਕ ਮਹਿੰਗੇ nested loop ਨੂੰ ਇੱਕ ਤੇਜ਼ "seek per row" ਪੈਟਰਨ ਵਿੱਚ ਬਦਲ ਸਕਦਾ ਹੈ। ਵਿਰੁੱਧ, ਗੈਰ-ਮੌਜੂਦ ਜਾਂ ਅਣਉਪਯੋਗ ਇੰਡੈਕਸ engine ਨੂੰ hash joins ਜਾਂ merge joins ਲਈ ਵੱਡੇ sorts ਵੱਲ dhakel ਸਕਦੇ ਹਨ।
ਡੇਟਾਬੇਸ ਸਿਰਫ SQL "ਚਲਾਉਂਦੇ" ਨਹੀਂ। ਉਹ ਇਸਨੂੰ ਕੰਪਾਈਲ ਕਰਦੇ ਹਨ। Ullman ਦਾ ਪ੍ਰਭਾਵ ਦੋਹਾਂ ਡੇਟਾਬੇਸ ਸਿਧਾਂਤ ਅਤੇ ਕੰਪਾਇਲਰ ਸੋਚ 'ਤੇ ਫੈਲਾ ਹੋਇਆ ਹੈ, ਅਤੇ ਇਹ ਜੋੜ ਇਹ ਸਮਝਾਉਂਦਾ ਹੈ ਕਿ query engines programming language toolchains ਵਰਗੇ ਕਿਉਂ ਵਰਤਦੇ ਹਨ: ਉਹ translate, rewrite, ਅਤੇ optimize ਕਰਦੇ ਹਨ ਹਰੇਕ ਅਮਲ ਤੋਂ ਪਹਿਲਾਂ।
ਜਦੋਂ ਤੁਸੀਂ ਇੱਕ ਕੁਇਰੀ ਭੇਜਦੇ ਹੋ, ਪਹਿਲਾ ਕਦਮ ਕੰਪਾਇਲਰ ਦੇ front end ਵਾਂਗ ਹੁੰਦਾ ਹੈ। ਇੰਜਨ keywords ਅਤੇ identifiers ਨੂੰ tokenise ਕਰਦਾ ਹੈ, grammar ਚੈੱਕ ਕਰਦਾ ਹੈ, ਅਤੇ ਇੱਕ parse tree ਬਣਾਉਂਦਾ ਹੈ (ਅਕਸਰ ਸਰਲ ਰੂਪ ਵਿੱਚ abstract syntax tree)। ਇਹੀ ਥਾਂ ਹੈ ਜਿੱਥੇ ਬੁਨਿਆਦੀ ਗਲਤੀਆਂ ਫੜੀਆਂ ਜਾਂਦੀਆਂ ਹਨ: ਗੁੰਮ ਹੋਏ ਕੋਮਾ, ambiguous column names, ਗਲਤ grouping ਨਿਯਮ ਆਦਿ।
ਇੱਕ ਸਹਾਈ ਮਾਨਸਿਕ ਮਾਡਲ: SQL ਇੱਕ ਪ੍ਰੋਗ੍ਰਾਮਿੰਗ ਭਾਸ਼ਾ ਹੈ ਜਿਸਦਾ "प्रੋਗ੍ਰਾਮ" ਡੇਟਾ ਸੰਬੰਧਾਂ ਨੂੰ ਵਰਣਨ ਕਰਦਾ ਹੈ ਨਾ ਕਿ ਲੂਪਾਂ ਨੂੰ।
ਕੰਪਾਇਲਰ syntax ਨੂੰ ਇੱਕ intermediate representation (IR) ਵਿੱਚ ਬਦਲਦੇ ਹਨ। ਡੇਟਾਬੇਸ ਵੀ ਕੁਝ ਇਸੇ ਤਰ੍ਹਾਂ ਕਰਦੇ ਹਨ: ਉਹ SQL syntax ਨੂੰ logical operators ਵਿੱਚ ਤਬਦੀਲ ਕਰਦੇ ਹਨ ਜਿਵੇਂ:
GROUP BY)ਉਹ ਲਾਜ਼ਮੀ ਰੂਪ SQL ਟੈਕਸਟ ਤੋਂ ਜ਼ਿਆਦਾ relational algebra ਦੇ ਨੇੜੇ ਹੁੰਦਾ ਹੈ, ਜੋ ਕਿ ਮਾਨਤਾ ਅਤੇ ਸਮਤੁਲਤਾ ਬਾਰੇ ਸੋਚਣਾ ਆਸਾਨ ਬਣਾਉਂਦਾ ਹੈ।
ਕੰਪਾਇਲਰ ਅਪਟੀਮਾਈਜ਼ੇਸ਼ਨ ਪ੍ਰੋਗ੍ਰਾਮ ਦੇ ਨਤੀਜੇ ਨੂੰ ਅਗੇ ਹੀ ਬਦਲ ਦੇਣ ਬਿਨਾਂ ਚਲਾਉਟ ਨੂੰ ਸਸਤਾ ਬਣਾਉਂਦੀ ਹੈ। ਡੇਟਾਬੇਸ ਓਪਟੀਮਾਈਜ਼ਰ ਵੀ ਇਹੀ ਕਰਦੇ ਹਨ, ਨਿਯਮ ਪ੍ਰਣਾਲੀ ਵਰਤ ਕੇ ਜਿਵੇਂ:
ਇਹ "dead code elimination" ਦਾ ਡੇਟਾਬੇਸ ਸੰਸਕਰਣ ਹੈ: ਇਕੋ ਫੈਲਸਫ਼ਾ—ਸੈਮਾਂਟਿਕਸ ਨੂੰ ਬਰਕਰਾਰ ਰੱਖਦੇ ਹੋਏ ਲਾਗਤ ਘਟਾਉਣਾ।
ਜੇ ਤੁਹਾਡੀ ਕੁਇਰੀ ਧੀਮੀ ਹੈ, ਤਾਂ ਸਿਰਫ SQL ਦੇਖੋ ਨਾ। query plan ਨੂੰ ਉਸ ਤਰ੍ਹਾਂ ਦੇਖੋ ਜਿਵੇਂ ਕਿ ਤੁਸੀਂ ਕੰਪਾਇਲਰ ਦੇ ਆਉਟਪੁੱਟ ਦੀ ਜਾਂਚ ਕਰ ਰਹੇ ਹੋ। ਇੱਕ ਯੋਜਨਾ ਦੱਸਦੀ ਹੈ ਕਿ ਇੰਜਨ ਨੇ ਅਸਲ ਵਿੱਚ ਕੀ ਚੁਣਿਆ: join order, index ਵਰਤੋਂ, ਅਤੇ ਕਿੱਥੇ ਸਮਾਂ ਲੱਗ ਰਿਹਾ ਹੈ।
ਪ੍ਰਾਇਕਟਿਕ ਨਤੀਜਾ: EXPLAIN ਆਉਟਪੁੱਟ ਨੂੰ ਪੜ੍ਹਨਾ ਇੱਕ ਪ੍ਰਦਰਸ਼ਨ “ਅਸੈਂਬਲੀ ਲਿਸਟਿੰਗ” ਵਾਂਗ ਸਿੱਖੋ। ਇਹ tuning ਨੂੰ ਅਨੁਮਾਨ-ਅਧਾਰਤ ਤੋਂ ਸਬੂਤ-ਆਧਾਰਿਤ ਡੀਬੱਗਿੰਗ ਬਣਾਉਂਦਾ।
Jeffrey Ullman ਨੇ ਇਸ ਗੱਲ ਨੂੰ ਫਾਰਮੈਲ ਕੀਤਾ ਕਿ ਡੇਟਾਬੇਸ ਕਿਸ ਤਰ੍ਹਾਂ ਕੁਇਰੀ ਦੀ ਮਾਨਤਾ ਨੂੰ ਦਰਸਾਉਂਦੇ ਹਨ ਅਤੇ ਕਿਵੇਂ ਉਹ ਕੁਇਰੀਆਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਢੰਗ ਨਾਲ ਤੇਜ਼ ਬਦਲੀ ਕਰ ਸਕਦੇ ਹਨ। ਇਹ ਬੁਨਿਆਦ ਹਰ ਵਾਰੀ ਸਾਹਮਣੇ ਆਉਂਦੀ ਹੈ ਜਦੋਂ ਇੰਜਨ ਇੱਕ ਕੁਇਰੀ ਨੂੰ ਰੀਰਾਈਟ ਕਰਦਾ, ਜੋਇਨਾਂ ਦੀ ਕ੍ਰਮਬੱਧਤਾ ਬਦਲਦਾ, ਜਾਂ ਵੱਖ-ਵੱਖ ਐਗਜ਼ਿਕਿਊਸ਼ਨ ਯੋਜਨਾ ਚੁਣਦਾ — ਪਰ ਨਤੀਜਾ ਇਕੋ ਹੀ ਰਹਿੰਦਾ।
Relational algebra ਉਹ ਛੋਟਾ ਸੈੱਟ ਹੈ (select, project, join, union, difference) ਜੋ ਕਿ ਕੁਇਰੀ ਦੇ ਨਤੀਜੇ ਨੂੰ ਸਪੱਸ਼ਟ ਤਰੀਕੇ ਨਾਲ ਦਰਸਾਉਂਦਾ ਹੈ। ਇੰਜਨਾਂ ਆਮ ਤੌਰ 'ਤੇ SQL ਨੂੰ ਇੱਕ algebra-ਨੁਮਾ ਓਪਰੇਟਰ ਟ੍ਰੀ ਵਿੱਚ ਬਦਲਦੇ ਹਨ ਤਾਂ ਜੋ ਉਹ ਸਮਤੁਲਤਾ ਨਿਯਮ (ਉਦਾਹਰਨ ਲਈ ਫਿਲਟਰ ਨੂੰ ਪਹਿਲਾਂ ਲਾਉਣਾ) ਲਗਾ ਸਕਣ ਅਤੇ ਫਿਰ ਇੱਕ কার্যਕਾਰੀ ਯੋਜਨਾ ਚੁਣ ਸਕਣ।
ਇਹ ਲਈ ਮਹੱਤਵਪੂਰਨ ਹੈ ਕਿਉਂਕਿ ਓਪਟਿਮਾਈਜ਼ਰ ਨੂੰ ਇਹ ਸਾਬਿਤ ਕਰਨਾ ਪੈਂਦਾ ਹੈ ਕਿ ਇੱਕ ਰੀਰਾਈਟ ਕੀਤੇ ਗਏ ਕੁਇਰੀ ਤੋਂ ਉਹੀ ਨਤੀਜੇ ਆਉਣਗੇ। ਸਮਤੁਲਤਾ ਨਿਯਮ ਓਪਟਿਮਾਈਜ਼ਰ ਨੂੰ ਇਹ ਕਰਨ ਦਿੰਦੇ ਹਨ, ਜਿਵੇਂ ਕਿ:
WHERE ਫਿਲਟਰ ਨੂੰ JOIN ਤੋਂ ਪਹਿਲਾਂ ਲਗਾਉਣਾਇਨ੍ਹਾਂ ਬਦਲਾਵਾਂ ਨਾਲ ਕੰਮ ਕਾਫੀ ਘਟ ਸਕਦਾ ਹੈ ਬਿਨਾਂ ਨਤੀਜੇ ਬਦਲੇ।
ਲਾਜ਼ਮੀ ਯੋਜਨਾ (logical plan) ٻڌਾਉਂਦੀ ਹੈ ਕਿ ਕੀ ਨਤੀਜਾ ਕੱਢਣਾ ਹੈ (filter, join, aggregate ਵਰਗੇ ਅਮਲ), ਜਦਕਿ ਭੌਤਿਕ ਯੋਜਨਾ (physical plan) ਇਹ ਦੱਸਦੀ ਹੈ ਕਿ ਉਹਨਾਂ ਨੂੰ ਕਿਵੇਂ ਚਲਾਇਆ ਜਾਵੇ (index scan vs full scan, hash join vs nested loop, ਪੈਰਲੇਲਿਸ਼ਨ ਆਦਿ)। ਜ਼ਿਆਦਾਤਰ ਪ੍ਰਦਰਸ਼ਨ ਫਰਕ ਭੌਤਿਕ ਚੋਣਾਂ ਤੋਂ ਆਉਂਦੇ ਹਨ, ਜੋ ਕਿ ਲਾਜ਼ਮੀ ਰੀਰਾਈਟਸ ਨਾਲ ਸੰਭਵ ਹੁੰਦੇ ਹਨ।
Cost-based optimization ਵੱਖ-ਵੱਖ ਵੈਧ ਯੋਜਨਾਵਾਂ ਦੀ ਤੁਲਨਾ ਕਰਦਾ ਅਤੇ ਉਹjenige ਚੁਣਦਾ ਹੈ ਜਿਸ ਦੀ ਲਾਗਤ ਸਭ ਤੋਂ ਘੱਟ ਅੰਦਾਜ਼ੇ ਮੁਤਾਬਕ ਲੱਗਦੀ ਹੈ। ਲਾਗਤ ਆਮ ਤੌਰ 'ਤੇ ਇਨ੍ਹਾਂ ਚੀਜ਼ਾਂ ਨਾਲ ਨਿਰਧਾਰਿਤ ਹੁੰਦੀ ਹੈ: ਪੈਕੇ ਪ੍ਰੋਸੈਸ ਕੀਤੀਆਂ ਵਾਰੀਆਂ, I/O, CPU, ਅਤੇ ਮੈਮੋਰੀ (ਜਿਵੇਂ ਕਿ ਕੀ hash ਜਾਂ sort ਡਿਸ্ক 'ਤੇ spill ਕਰਦਾ ਹੈ)।
Cardinality estimation optimizer ਦਾ ਅੰਦਾਜ਼ਾ ਹੈ ਕਿ “ਇਸ ਕਦਮ ਤੋਂ ਕਿੰਨੀ ਲਾਈਨਾਂ ਨਿਕਲਣਗੀਆਂ?” ਇਹ ਅੰਦਾਜ਼ੇ JOIN ਕ੍ਰਮ, JOIN ਕਿਸਮ, ਅਤੇ index scan ਦੀ ਵਰਤੋਂ ਤੇ ਪ੍ਰਭਾਵ ਪਾਂਦੇ ਹਨ। ਜਦੋਂ ਅੰਦਾਜ਼ੇ ਗਲਤ ਹੁੰਦੇ ਹਨ (ਅਕਸਰ stale/ਗੈਰ-ਮੌਜੂਦ statistics ਕਾਰਨ), ਤਾਂ ਪਲੈਨ ਇਕਦਮ ਮਹਿੰਗਾ ਹੋ ਸਕਦਾ ਹੈ—ਚੋਟੀ ਦੇ ਲੱਛਣਾਂ ਵਿੱਚ ਅਚਾਨਕ ਧੀਮਾ ਹੋਣਾ, ਵੱਡੇ spills, ਜਾਂ ਅਣਉਮੀਦ ਰੂਪ ਵਿੱਚ ਯੋਜਨਾ ਬਦਲਣਾ ਸ਼ਾਮਲ ਹਨ।
ਕੁਝ ਉੱਚ-ਸੰਕੇਤ ਚੀਜ਼ਾਂ ਤੇ ਧਿਆਨ ਦੇਓ:
ਯੋਜਨਾ ਨੂੰ ਇਕ ਕੰਪਾਇਲ ਕਰ ਲਏ ਸਮਾਨ assembly ਲਿਸਟ ਦੀ ਤਰ੍ਹਾਂ ਪੜ੍ਹੋ: ਇਹ ਦੱਸਦੀ ਹੈ ਕਿ ਇੰਜਨ ਨੇ ਅਸਲ ਵਿੱਚ ਕੀ ਚੁਣਿਆ।
Normalisation ਦੁਹਰਾਈਆਂ ਨੂੰ ਘਟਾਉਂਦੀ ਅਤੇ update anomalies ਨੂੰ ਰੋਕਦੀ ਹੈ, ਜਿਸ ਨਾਲ ਟੇਬਲ ਅਤੇ ਇੰਡੈਕਸ ਛੋਟੇ ਰਹਿੰਦੇ ਹਨ ਅਤੇ joins ਅਧਿਕ ਭਰੋਸੇਮੰਦ ਹੁੰਦੇ ਹਨ। Denormalization ਠੀਕ ਹੈ ਜਦੋਂ ਤੁਸੀਂ analytics-heavy ਟੇਬਲ ਬਣਾਉਂਦੇ ਹੋ, joins ਬੋਤਲਨੈਕ ਬਣ ਰਹੇ ਹੋ, ਅਤੇ ਤੁਸੀਂ controlled redundancy ਸਵੀਕਾਰ ਕਰ ਸਕਦੇ ਹੋ—ਪਰ ਇਹ ਜਾਣ-ਬੂਝ ਕੇ ਕੀਤਾ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ ਅਤੇ duplicates ਨੂੰ sync ਰੱਖਣ ਦੀ ਪ੍ਰਕਿਰਿਆ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ।
ਸਕੇਲ ਅਕਸਰ ਭੌਤਿਕ ਲੇਆਉਟ ਅਤੇ ਯੋਜਨਾ ਚੋਣ ਦਾ ਮਾਮਲਾ ਹੁੰਦਾ ਹੈ। ਆਮ ਤੌਰ 'ਤੇ ਵਰਤੋਂ ਵਿੱਚ ਰਹਿਣ ਵਾਲੇ ਤਰੀਕੇ ਹਨ:
Caching ਦੁਹਰਾਈ ਪੜ੍ਹਾਈਆਂ ਨੂੰ ਤੇਜ਼ ਕਰ ਸਕਦਾ ਹੈ, ਪਰ ਜੇ ਕੁਇਰੀ ਬਹੁਤ ਸਾਰਾ ਡੇਟਾ ਛੇੜਦੀ ਹੈ ਜਾਂ ਵੱਡੇ ਮਿਲ intermediate results ਬਣਾਉਂਦੀ ਹੈ, ਤਾਂ ਕੇਵਲ cache ਨੁਕਸਾਨ ਨੂੰ ਠੀਕ ਨਹੀਂ ਕਰੇਗੀ।