2011-10-30 42 views
27

我對一個看似簡單的概念感到困惑。 Mysql的定義確定性函數爲mysql中的確定性函數

總是產生相同的結果對於相同的輸入參數

所以,在我的理解的功能,功能類似於

CREATE FUNCTION foo (val INT) READS SQL DATA 
BEGIN 
    DECLARE retval INT; 
    SET retval = (SELECT COUNT(*) FROM table_1 WHERE field_1 = val); 
    RETURN retval; 
END; 

不確定性(有不保證在2次調用函數之間不會發生刪除/更新/插入操作)。同時,我看到很多功能幾乎相同,即基於查詢結果的返回值,並聲明爲DETERMINISTIC。看起來我錯過了一些非常基本的東西。

任何人都可以澄清這個問題嗎?

謝謝。

更新 感謝那些回答(+1)的人;到目前爲止,它似乎有一個廣泛的濫用DETERMINISTIC關鍵字。我很難相信有這麼多人這樣做,所以我會稍微等待其他答案。

+0

你能說出你正在談論的「許多功能」的例子嗎? – Mat

+0

@Mat:例如http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html(在用戶註釋部分,搜索「CREATE FUNCTION db.fnfullname」 - 它從數據庫爲傳遞的ID並返回基於select的結果的值)。 – a1ex07

+0

「...用戶評論...」...你有一些真正的mysql功能? – Mat

回答

14

從MySQL 5.0中參考:

例行性質的評估是基於創建者的「誠」:MySQL不檢查一個例程宣佈確定性是自由產生不確定的語句結果。但是,錯誤地聲明例程可能會影響結果或影響性能。將一個不確定的例程聲明爲DETERMINISTIC可能會導致優化器做出不正確的執行計劃選擇,從而導致意外的結果。將確定性程序聲明爲NONDETERMINISTIC可能會導致可用的優化不被使用,從而降低性能。在MySQL 5.0.44之前,DETERMINISTIC特性被接受,但不被優化器使用。

所以你有它,你可以標記存儲例程爲DETERMINISTIC,即使它不是,但它可能會導致意想不到的結果或性能問題。

+3

所以我們可能總有50%的機會選錯了一個?大。大聲笑你的評論幫助我更多地理解它。 – Cesar

+0

在「嵌套集模型」中,例如。 http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/我正在使用例程插入和刪除節點。 1)我們能否考慮在插入點(選定節點作爲參考)右邊(後面)更新所有節點邊界(將實際邊界加2)爲DETERMINISTIC? 2)因此也破壞一個節點? 3)將節點移動到其實際位置的左側? 4)移動一個節點的權利是它的實際位置? – llange

+0

爲什麼這是一個功能?也許更快的編譯,如果一個函數是真正的確定性像'3 + x = output'? –

2

你不會錯過任何東西。這個功能是非確定性的。聲明確定性不會導致數據庫融化,但可能會影響性能。 From the MySQL site:「聲明不確定性例程爲DETERMINISTIC可能會導致優化器做出錯誤的執行計劃選擇,從而導致意外的結果。」但是MySQL並沒有執行或檢查你所聲明的確定性例程是否確實是確定性的--- MySQL相信你知道你在做什麼。

+1

該例程是確定性的,因爲如果您在兩個相同的數據庫上執行此例程,結果將始終相同。 – bikeman868

8

DETERMINISTIC結果並不是指在不同時間返回的不同結果集(取決於同時添加了哪些數據)。此外,它是對使用相同數據的不同機器上的結果集的引用。例如,如果您有2臺運行包括uuid()或引用服務器變量的功能的機器,則應將它們視爲不確定。例如在複製中這很有用,因爲函數調用存儲在二進制日誌(主機)中,然後也由從機執行。有關詳細信息和示例,請參見http://dev.mysql.com/doc/refman/5.0/en/stored-programs-logging.html

因此,DETERMINISTIC的使用(99%的時間)是正確的,不被視爲誤用。

+0

來自mysql:'如果一個例程對於相同的輸入參數總是產生相同的結果,那麼它就被認爲是「確定性的」,否則就是「不確定性的」。來自其他來源的「確定性函數」的定義也「總是爲相同的參數返回相同的結果」。使用特定的DML(至少是SELECT)在函數體內是一個完全有效的操作。如果你說它沒有引用不同的結果集,那麼所有的定義都是錯誤的,因爲'always'意味着函數體內所有可能的有效語句。 – a1ex07

+0

「產生相同的結果」意味着在數據庫中產生相同的結果。這並不意味着返回相同的結果集。爲什麼MySQL會關心結果集是否每次都不一樣?但是,如果結果存儲的數據不同,它確實在意 - 請參閱我的答案以獲取更多詳細信息。 – bikeman868

+0

我欣賞Jon Gilbert和bikeman868的答案......我希望有一些官方消息來源支持他們。 23k代表某人的[這個dba.stackexchange.com的答案](https://dba.stackexchange.com/questions/4079/mysql-deterministic-procedures/4080#4080)給出了相反的答案。 –

0

如果您打開了複製或可能在一天內使用複製,則確定性非常重要。例如,導致行更改(更新或插入)的非確定性函數調用將需要使用二進制(基於行)複製,其中作爲確定性函數可以基於語句進行復制。 查看上面的SQL示例時,這會變得很有趣,當使用基於語句進行復制時哪些應用會發生相同的結果(給出相​​同的結果),哪些應該使用master(基於行)獲得的結果進行復制。如果語句使用適當的鎖定執行,並且可以保證在從服務器上以相同的順序執行,那麼它們確實是確定性的。如果Slave使用的鎖定/語句順序(沒有併發性,按照它們開始的順序對語句進行串行處理)意味着答案可能不同,那麼函數應該是非確定性的。

3

我認爲你的例程是確定性的。文件不是很清楚,這導致許多人對這個問題感到非常困惑,實際上這更多的是關於複製的問題。

考慮在兩個數據庫之間建立複製的情況。 master數據庫保存所有已執行的存儲例程(包括其輸入參數)的日誌,並將該日誌發送給從站。從站使用相同的輸入參數以相同的順序執行相同的存儲例程。從屬數據庫現在是否包含與主數據庫相同的數據?如果存儲的例程創建GUID並將它們存儲在數據庫中,那麼否,主數據庫和從數據庫將不同,並且複製將被打破。

DETERMINISTIC標誌的主要目的是告訴MySQL,在複製日誌中是否包含對此存儲例程的調用將導致主數據庫和複製的從站之間的差異,因此是不安全的。

當決定DETERMINISTIC標誌是否適合存儲例程時,可以這樣想:如果我從兩個相同的數據庫開始,並且在兩個數據庫上使用相同的輸入參數執行我的例程,我的數據庫是否仍然相同?如果他們是那麼我的例程是確定性的。

如果你聲明你的例程是確定性的,那麼你的主數據庫的副本可能與原始數據庫的副本不一樣,因爲MySQL只會將過程調用添加到複製日誌中,並且在從服務器上執行該過程不會產生相同的結果。

如果您的例程不確定,那麼MySQL必須將受影響的行包含在複製日誌中。如果您將例程聲明爲非確定性,則不會破壞任何內容,但只要過程調用已足夠且這可能會影響性能,複製日誌將包含所有受影響的行。